Treeify bells and minecarts

- Use InstanceTrees in BellVisual and MinecartVisual
- Use JOML Matrix4fStack instead of PoseStack
- Directly transform Matrix4f instead of using PoseStack to compute initial pose
This commit is contained in:
PepperCode1 2024-09-15 13:27:08 -07:00
parent ed727e7a1b
commit 904933e22e
10 changed files with 146 additions and 139 deletions

View File

@ -73,6 +73,12 @@ public class PosedInstance extends ColoredLitInstance implements Transform<Posed
return this; return this;
} }
public PosedInstance setTransform(Matrix4fc pose, Matrix3fc normal) {
this.pose.set(pose);
this.normal.set(normal);
return this;
}
public PosedInstance setTransform(PoseStack.Pose pose) { public PosedInstance setTransform(PoseStack.Pose pose) {
this.pose.set(pose.pose()); this.pose.set(pose.pose());
normal.set(pose.normal()); normal.set(pose.normal());

View File

@ -1,6 +1,7 @@
package dev.engine_room.flywheel.lib.instance; package dev.engine_room.flywheel.lib.instance;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.joml.Quaternionfc; import org.joml.Quaternionfc;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
@ -40,6 +41,11 @@ public class TransformedInstance extends ColoredLitInstance implements Affine<Tr
return this; return this;
} }
public TransformedInstance setTransform(Matrix4fc pose) {
this.pose.set(pose);
return this;
}
public TransformedInstance setTransform(PoseStack.Pose pose) { public TransformedInstance setTransform(PoseStack.Pose pose) {
this.pose.set(pose.pose()); this.pose.set(pose.pose());
return this; return this;

View File

@ -193,7 +193,7 @@ public final class InstanceTree {
affine.rotate(tempQuaternion.rotationZYX(zRot, yRot, xRot)); affine.rotate(tempQuaternion.rotationZYX(zRot, yRot, xRot));
} }
if (xScale != 1.0F || yScale != 1.0F || zScale != 1.0F) { if (xScale != ModelPart.DEFAULT_SCALE || yScale != ModelPart.DEFAULT_SCALE || zScale != ModelPart.DEFAULT_SCALE) {
affine.scale(xScale, yScale, zScale); affine.scale(xScale, yScale, zScale);
} }
} }
@ -300,13 +300,6 @@ public final class InstanceTree {
return zScale; return zScale;
} }
public void pos(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
setChanged();
}
public void xPos(float x) { public void xPos(float x) {
this.x = x; this.x = x;
setChanged(); setChanged();
@ -322,10 +315,10 @@ public final class InstanceTree {
setChanged(); setChanged();
} }
public void rotation(float xRot, float yRot, float zRot) { public void pos(float x, float y, float z) {
this.xRot = xRot; this.x = x;
this.yRot = yRot; this.y = y;
this.zRot = zRot; this.z = z;
setChanged(); setChanged();
} }
@ -344,10 +337,10 @@ public final class InstanceTree {
setChanged(); setChanged();
} }
public void scale(float xScale, float yScale, float zScale) { public void rotation(float xRot, float yRot, float zRot) {
this.xScale = xScale; this.xRot = xRot;
this.yScale = yScale; this.yRot = yRot;
this.zScale = zScale; this.zRot = zRot;
setChanged(); setChanged();
} }
@ -366,6 +359,13 @@ public final class InstanceTree {
setChanged(); setChanged();
} }
public void scale(float xScale, float yScale, float zScale) {
this.xScale = xScale;
this.yScale = yScale;
this.zScale = zScale;
setChanged();
}
public void offsetPos(float xOffset, float yOffset, float zOffset) { public void offsetPos(float xOffset, float yOffset, float zOffset) {
x += xOffset; x += xOffset;
y += yOffset; y += yOffset;
@ -388,6 +388,10 @@ public final class InstanceTree {
setChanged(); setChanged();
} }
public void offsetPos(Vector3fc offset) {
offsetPos(offset.x(), offset.y(), offset.z());
}
public void offsetRotation(float xOffset, float yOffset, float zOffset) { public void offsetRotation(float xOffset, float yOffset, float zOffset) {
xRot += xOffset; xRot += xOffset;
yRot += yOffset; yRot += yOffset;
@ -410,6 +414,10 @@ public final class InstanceTree {
setChanged(); setChanged();
} }
public void offsetRotation(Vector3fc offset) {
offsetRotation(offset.x(), offset.y(), offset.z());
}
public void offsetScale(float xOffset, float yOffset, float zOffset) { public void offsetScale(float xOffset, float yOffset, float zOffset) {
xScale += xOffset; xScale += xOffset;
yScale += yOffset; yScale += yOffset;
@ -432,14 +440,6 @@ public final class InstanceTree {
setChanged(); setChanged();
} }
public void offsetPos(Vector3fc offset) {
offsetPos(offset.x(), offset.y(), offset.z());
}
public void offsetRotation(Vector3fc offset) {
offsetRotation(offset.x(), offset.y(), offset.z());
}
public void offsetScale(Vector3fc offset) { public void offsetScale(Vector3fc offset) {
offsetScale(offset.x(), offset.y(), offset.z()); offsetScale(offset.x(), offset.y(), offset.z());
} }
@ -491,6 +491,10 @@ public final class InstanceTree {
setChanged(); setChanged();
} }
private void setChanged() {
changed = true;
}
public void delete() { public void delete() {
if (instance != null) { if (instance != null) {
instance.delete(); instance.delete();
@ -500,10 +504,6 @@ public final class InstanceTree {
} }
} }
private void setChanged() {
changed = true;
}
@ApiStatus.Experimental @ApiStatus.Experimental
@FunctionalInterface @FunctionalInterface
public interface ObjIntIntConsumer<T> { public interface ObjIntIntConsumer<T> {

View File

@ -99,6 +99,10 @@ public abstract class AbstractBlockEntityVisual<T extends BlockEntity> extends A
.shouldUpdate(pos.distToCenterSqr(context.camera().getPosition())); .shouldUpdate(pos.distToCenterSqr(context.camera().getPosition()));
} }
protected int computePackedLight() {
return LevelRenderer.getLightColor(level, pos);
}
protected void relight(BlockPos pos, @Nullable FlatLit... instances) { protected void relight(BlockPos pos, @Nullable FlatLit... instances) {
FlatLit.relight(LevelRenderer.getLightColor(level, pos), instances); FlatLit.relight(LevelRenderer.getLightColor(level, pos), instances);
} }

View File

@ -92,11 +92,14 @@ public abstract class AbstractEntityVisual<T extends Entity> extends AbstractVis
return entity.noCulling || visibilityTester.check(frustum); return entity.noCulling || visibilityTester.check(frustum);
} }
protected void relight(float partialTick, @Nullable FlatLit... instances) { protected int computePackedLight(float partialTick) {
BlockPos pos = BlockPos.containing(entity.getLightProbePosition(partialTick)); BlockPos pos = BlockPos.containing(entity.getLightProbePosition(partialTick));
int blockLight = entity.isOnFire() ? 15 : level.getBrightness(LightLayer.BLOCK, pos); int blockLight = entity.isOnFire() ? 15 : level.getBrightness(LightLayer.BLOCK, pos);
int skyLight = level.getBrightness(LightLayer.SKY, pos); int skyLight = level.getBrightness(LightLayer.SKY, pos);
int light = LightTexture.pack(blockLight, skyLight); return LightTexture.pack(blockLight, skyLight);
FlatLit.relight(light, instances); }
protected void relight(float partialTick, @Nullable FlatLit... instances) {
FlatLit.relight(computePackedLight(partialTick), instances);
} }
} }

View File

@ -2,23 +2,22 @@ package dev.engine_room.flywheel.vanilla;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.joml.AxisAngle4f; import org.joml.Matrix4f;
import org.joml.Quaternionf; import org.joml.Matrix4fc;
import org.joml.Vector3f;
import dev.engine_room.flywheel.api.instance.Instance; import dev.engine_room.flywheel.api.instance.Instance;
import dev.engine_room.flywheel.api.material.Material; import dev.engine_room.flywheel.api.material.Material;
import dev.engine_room.flywheel.api.model.Model;
import dev.engine_room.flywheel.api.visualization.VisualizationContext; import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import dev.engine_room.flywheel.lib.instance.InstanceTypes;
import dev.engine_room.flywheel.lib.instance.OrientedInstance;
import dev.engine_room.flywheel.lib.material.SimpleMaterial; import dev.engine_room.flywheel.lib.material.SimpleMaterial;
import dev.engine_room.flywheel.lib.model.ModelHolder; import dev.engine_room.flywheel.lib.model.RetexturedMesh;
import dev.engine_room.flywheel.lib.model.SingleMeshModel; import dev.engine_room.flywheel.lib.model.part.InstanceTree;
import dev.engine_room.flywheel.lib.model.part.ModelPartConverter;
import dev.engine_room.flywheel.lib.visual.AbstractBlockEntityVisual; import dev.engine_room.flywheel.lib.visual.AbstractBlockEntityVisual;
import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual; import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual;
import net.minecraft.client.model.geom.ModelLayers; import net.minecraft.client.model.geom.ModelLayers;
import net.minecraft.client.renderer.blockentity.BellRenderer; import net.minecraft.client.renderer.blockentity.BellRenderer;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.level.block.entity.BellBlockEntity; import net.minecraft.world.level.block.entity.BellBlockEntity;
@ -27,29 +26,28 @@ public class BellVisual extends AbstractBlockEntityVisual<BellBlockEntity> imple
.mipmap(false) .mipmap(false)
.build(); .build();
private static final ModelHolder BELL_MODEL = new ModelHolder(() -> { private final InstanceTree instances;
return new SingleMeshModel(ModelPartConverter.convert(ModelLayers.BELL, BellRenderer.BELL_RESOURCE_LOCATION.sprite(), "bell_body"), MATERIAL); private final InstanceTree bellBody;
});
private final OrientedInstance bell; private final Matrix4fc initialPose;
private boolean wasShaking = false; private boolean wasShaking = false;
public BellVisual(VisualizationContext ctx, BellBlockEntity blockEntity, float partialTick) { public BellVisual(VisualizationContext ctx, BellBlockEntity blockEntity, float partialTick) {
super(ctx, blockEntity, partialTick); super(ctx, blockEntity, partialTick);
bell = createBellInstance().pivot(0.5f, 0.75f, 0.5f) TextureAtlasSprite sprite = BellRenderer.BELL_RESOURCE_LOCATION.sprite();
.position(getVisualPosition()); instances = InstanceTree.create(instancerProvider(), ModelLayers.BELL, (path, mesh) -> {
bell.setChanged(); return new Model.ConfiguredMesh(MATERIAL, new RetexturedMesh(mesh, sprite));
});
bellBody = instances.childOrThrow("bell_body");
BlockPos visualPos = getVisualPosition();
initialPose = new Matrix4f().translate(visualPos.getX(), visualPos.getY(), visualPos.getZ());
updateRotation(partialTick); updateRotation(partialTick);
} }
private OrientedInstance createBellInstance() {
return instancerProvider().instancer(InstanceTypes.ORIENTED, BELL_MODEL.get())
.createInstance();
}
@Override @Override
public void beginFrame(Context context) { public void beginFrame(Context context) {
if (doDistanceLimitThisFrame(context) || !isVisible(context.frustum())) { if (doDistanceLimitThisFrame(context) || !isVisible(context.frustum())) {
@ -60,37 +58,46 @@ public class BellVisual extends AbstractBlockEntityVisual<BellBlockEntity> imple
} }
private void updateRotation(float partialTick) { private void updateRotation(float partialTick) {
float xRot = 0;
float zRot = 0;
if (blockEntity.shaking) { if (blockEntity.shaking) {
float ringTime = (float) blockEntity.ticks + partialTick; float ringTime = (float) blockEntity.ticks + partialTick;
float angle = Mth.sin(ringTime / (float) Math.PI) / (4.0F + ringTime / 3.0F); float angle = Mth.sin(ringTime / (float) Math.PI) / (4.0F + ringTime / 3.0F);
Vector3f ringAxis = blockEntity.clickDirection.getCounterClockWise() switch (blockEntity.clickDirection) {
.step(); case NORTH -> xRot = -angle;
case SOUTH -> xRot = angle;
bell.rotation(new Quaternionf(new AxisAngle4f(angle, ringAxis))) case EAST -> zRot = -angle;
.setChanged(); case WEST -> zRot = angle;
}
wasShaking = true; wasShaking = true;
} else if (wasShaking) { } else if (wasShaking) {
bell.rotation(new Quaternionf())
.setChanged();
wasShaking = false; wasShaking = false;
} }
bellBody.xRot(xRot);
bellBody.zRot(zRot);
instances.updateInstancesStatic(initialPose);
} }
@Override @Override
public void updateLight(float partialTick) { public void updateLight(float partialTick) {
relight(bell); int packedLight = computePackedLight();
instances.traverse(instance -> {
instance.light(packedLight)
.setChanged();
});
} }
@Override @Override
public void collectCrumblingInstances(Consumer<Instance> consumer) { public void collectCrumblingInstances(Consumer<Instance> consumer) {
consumer.accept(bell); instances.traverse(consumer);
} }
@Override @Override
protected void _delete() { protected void _delete() {
bell.delete(); instances.delete();
} }
} }

View File

@ -6,19 +6,17 @@ import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import org.joml.Matrix4fc; import org.joml.Matrix4fc;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import dev.engine_room.flywheel.api.instance.Instance; import dev.engine_room.flywheel.api.instance.Instance;
import dev.engine_room.flywheel.api.material.Material;
import dev.engine_room.flywheel.api.model.Model; import dev.engine_room.flywheel.api.model.Model;
import dev.engine_room.flywheel.api.visualization.VisualizationContext; import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import dev.engine_room.flywheel.lib.material.CutoutShaders; import dev.engine_room.flywheel.lib.material.CutoutShaders;
import dev.engine_room.flywheel.lib.material.SimpleMaterial; import dev.engine_room.flywheel.lib.material.SimpleMaterial;
import dev.engine_room.flywheel.lib.model.RetexturedMesh; import dev.engine_room.flywheel.lib.model.RetexturedMesh;
import dev.engine_room.flywheel.lib.model.part.InstanceTree; import dev.engine_room.flywheel.lib.model.part.InstanceTree;
import dev.engine_room.flywheel.lib.transform.TransformStack;
import dev.engine_room.flywheel.lib.visual.AbstractBlockEntityVisual; import dev.engine_room.flywheel.lib.visual.AbstractBlockEntityVisual;
import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual; import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual;
import it.unimi.dsi.fastutil.floats.Float2FloatFunction; import it.unimi.dsi.fastutil.floats.Float2FloatFunction;
@ -29,7 +27,9 @@ import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.Sheets; import net.minecraft.client.renderer.Sheets;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos; import net.minecraft.core.SectionPos;
import net.minecraft.util.Mth;
import net.minecraft.world.level.block.AbstractChestBlock; import net.minecraft.world.level.block.AbstractChestBlock;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.ChestBlock; import net.minecraft.world.level.block.ChestBlock;
@ -40,7 +40,7 @@ import net.minecraft.world.level.block.entity.LidBlockEntity;
import net.minecraft.world.level.block.state.properties.ChestType; import net.minecraft.world.level.block.state.properties.ChestType;
public class ChestVisual<T extends BlockEntity & LidBlockEntity> extends AbstractBlockEntityVisual<T> implements SimpleDynamicVisual { public class ChestVisual<T extends BlockEntity & LidBlockEntity> extends AbstractBlockEntityVisual<T> implements SimpleDynamicVisual {
private static final dev.engine_room.flywheel.api.material.Material MATERIAL = SimpleMaterial.builder() private static final Material MATERIAL = SimpleMaterial.builder()
.cutout(CutoutShaders.ONE_TENTH) .cutout(CutoutShaders.ONE_TENTH)
.texture(Sheets.CHEST_SHEET) .texture(Sheets.CHEST_SHEET)
.mipmap(false) .mipmap(false)
@ -84,14 +84,7 @@ public class ChestVisual<T extends BlockEntity & LidBlockEntity> extends Abstrac
lid = instances.childOrThrow("lid"); lid = instances.childOrThrow("lid");
lock = instances.childOrThrow("lock"); lock = instances.childOrThrow("lock");
PoseStack poseStack = new PoseStack(); initialPose = createInitialPose();
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); neighborCombineResult = chestBlock.combine(blockState, level, pos, true);
lidProgress = neighborCombineResult.apply(ChestBlock.opennessCombiner(blockEntity)); lidProgress = neighborCombineResult.apply(ChestBlock.opennessCombiner(blockEntity));
@ -112,6 +105,15 @@ public class ChestVisual<T extends BlockEntity & LidBlockEntity> extends Abstrac
return calendar.get(Calendar.MONTH) + 1 == 12 && calendar.get(Calendar.DATE) >= 24 && calendar.get(Calendar.DATE) <= 26; return calendar.get(Calendar.MONTH) + 1 == 12 && calendar.get(Calendar.DATE) >= 24 && calendar.get(Calendar.DATE) <= 26;
} }
private Matrix4f createInitialPose() {
BlockPos visualPos = getVisualPosition();
float horizontalAngle = blockState.getValue(ChestBlock.FACING).toYRot();
return new Matrix4f().translate(visualPos.getX(), visualPos.getY(), visualPos.getZ())
.translate(0.5F, 0.5F, 0.5F)
.rotateY(-horizontalAngle * Mth.DEG_TO_RAD)
.translate(-0.5F, -0.5F, -0.5F);
}
@Override @Override
public void setSectionCollector(SectionCollector sectionCollector) { public void setSectionCollector(SectionCollector sectionCollector) {
this.lightSections = sectionCollector; this.lightSections = sectionCollector;

View File

@ -1,22 +1,19 @@
package dev.engine_room.flywheel.vanilla; package dev.engine_room.flywheel.vanilla;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import com.mojang.blaze3d.vertex.PoseStack; import org.joml.Matrix4fStack;
import com.mojang.math.Axis;
import dev.engine_room.flywheel.api.material.Material; import dev.engine_room.flywheel.api.material.Material;
import dev.engine_room.flywheel.api.visual.DynamicVisual; import dev.engine_room.flywheel.api.visual.DynamicVisual;
import dev.engine_room.flywheel.api.visual.TickableVisual; import dev.engine_room.flywheel.api.visual.TickableVisual;
import dev.engine_room.flywheel.api.visualization.VisualizationContext; import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import dev.engine_room.flywheel.lib.instance.FlatLit;
import dev.engine_room.flywheel.lib.instance.InstanceTypes; import dev.engine_room.flywheel.lib.instance.InstanceTypes;
import dev.engine_room.flywheel.lib.instance.TransformedInstance; import dev.engine_room.flywheel.lib.instance.TransformedInstance;
import dev.engine_room.flywheel.lib.material.SimpleMaterial; import dev.engine_room.flywheel.lib.material.SimpleMaterial;
import dev.engine_room.flywheel.lib.model.ModelHolder;
import dev.engine_room.flywheel.lib.model.Models; import dev.engine_room.flywheel.lib.model.Models;
import dev.engine_room.flywheel.lib.model.SingleMeshModel; import dev.engine_room.flywheel.lib.model.part.InstanceTree;
import dev.engine_room.flywheel.lib.model.part.ModelPartConverter;
import dev.engine_room.flywheel.lib.util.RecyclingPoseStack;
import dev.engine_room.flywheel.lib.visual.ComponentEntityVisual; import dev.engine_room.flywheel.lib.visual.ComponentEntityVisual;
import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual; import dev.engine_room.flywheel.lib.visual.SimpleDynamicVisual;
import dev.engine_room.flywheel.lib.visual.SimpleTickableVisual; import dev.engine_room.flywheel.lib.visual.SimpleTickableVisual;
@ -24,7 +21,6 @@ import dev.engine_room.flywheel.lib.visual.component.FireComponent;
import dev.engine_room.flywheel.lib.visual.component.HitboxComponent; import dev.engine_room.flywheel.lib.visual.component.HitboxComponent;
import dev.engine_room.flywheel.lib.visual.component.ShadowComponent; import dev.engine_room.flywheel.lib.visual.component.ShadowComponent;
import net.minecraft.client.model.geom.ModelLayerLocation; import net.minecraft.client.model.geom.ModelLayerLocation;
import net.minecraft.client.model.geom.ModelLayers;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.entity.vehicle.AbstractMinecart; import net.minecraft.world.entity.vehicle.AbstractMinecart;
@ -39,31 +35,19 @@ public class MinecartVisual<T extends AbstractMinecart> extends ComponentEntityV
.mipmap(false) .mipmap(false)
.build(); .build();
public static final ModelHolder CHEST_BODY_MODEL = createBodyModelHolder(ModelLayers.CHEST_MINECART); private final InstanceTree instances;
public static final ModelHolder COMMAND_BLOCK_BODY_MODEL = createBodyModelHolder(ModelLayers.COMMAND_BLOCK_MINECART);
public static final ModelHolder FURNACE_BODY_MODEL = createBodyModelHolder(ModelLayers.FURNACE_MINECART);
public static final ModelHolder HOPPER_BODY_MODEL = createBodyModelHolder(ModelLayers.HOPPER_MINECART);
public static final ModelHolder STANDARD_BODY_MODEL = createBodyModelHolder(ModelLayers.MINECART);
public static final ModelHolder SPAWNER_BODY_MODEL = createBodyModelHolder(ModelLayers.SPAWNER_MINECART);
public static final ModelHolder TNT_BODY_MODEL = createBodyModelHolder(ModelLayers.TNT_MINECART);
private final TransformedInstance body;
@Nullable @Nullable
private TransformedInstance contents; private TransformedInstance contents;
private final ModelHolder bodyModel; private final Matrix4fStack stack = new Matrix4fStack(2);
private final RecyclingPoseStack stack = new RecyclingPoseStack();
private BlockState blockState; private BlockState blockState;
private boolean active; private boolean active;
public MinecartVisual(VisualizationContext ctx, T entity, float partialTick, ModelHolder bodyModel) { public MinecartVisual(VisualizationContext ctx, T entity, float partialTick, ModelLayerLocation layerLocation) {
super(ctx, entity, partialTick); super(ctx, entity, partialTick);
this.bodyModel = bodyModel; instances = InstanceTree.create(instancerProvider(), layerLocation, MATERIAL);
body = createBodyInstance();
blockState = entity.getDisplayBlockState(); blockState = entity.getDisplayBlockState();
contents = createContentsInstance(); contents = createContentsInstance();
@ -75,23 +59,12 @@ public class MinecartVisual<T extends AbstractMinecart> extends ComponentEntityV
updateLight(partialTick); updateLight(partialTick);
} }
private static ModelHolder createBodyModelHolder(ModelLayerLocation layer) {
return new ModelHolder(() -> {
return new SingleMeshModel(ModelPartConverter.convert(layer), MATERIAL);
});
}
private TransformedInstance createBodyInstance() {
return instancerProvider().instancer(InstanceTypes.TRANSFORMED, bodyModel.get())
.createInstance();
}
@Nullable @Nullable
private TransformedInstance createContentsInstance() { private TransformedInstance createContentsInstance() {
RenderShape shape = blockState.getRenderShape(); RenderShape shape = blockState.getRenderShape();
if (shape == RenderShape.ENTITYBLOCK_ANIMATED) { if (shape == RenderShape.ENTITYBLOCK_ANIMATED) {
body.setZeroTransform(); instances.traverse(instance -> instance.setZeroTransform().setChanged());
active = false; active = false;
return null; return null;
} }
@ -135,14 +108,14 @@ public class MinecartVisual<T extends AbstractMinecart> extends ComponentEntityV
} }
private void updateInstances(float partialTick) { private void updateInstances(float partialTick) {
stack.setIdentity(); stack.identity();
double posX = Mth.lerp(partialTick, entity.xOld, entity.getX()); double posX = Mth.lerp(partialTick, entity.xOld, entity.getX());
double posY = Mth.lerp(partialTick, entity.yOld, entity.getY()); double posY = Mth.lerp(partialTick, entity.yOld, entity.getY());
double posZ = Mth.lerp(partialTick, entity.zOld, entity.getZ()); double posZ = Mth.lerp(partialTick, entity.zOld, entity.getZ());
var renderOrigin = renderOrigin(); var renderOrigin = renderOrigin();
stack.translate(posX - renderOrigin.getX(), posY - renderOrigin.getY(), posZ - renderOrigin.getZ()); stack.translate((float) (posX - renderOrigin.getX()), (float) (posY - renderOrigin.getY()), (float) (posZ - renderOrigin.getZ()));
float yaw = Mth.lerp(partialTick, entity.yRotO, entity.getYRot()); float yaw = Mth.lerp(partialTick, entity.yRotO, entity.getYRot());
long randomBits = entity.getId() * 493286711L; long randomBits = entity.getId() * 493286711L;
@ -166,7 +139,7 @@ public class MinecartVisual<T extends AbstractMinecart> extends ComponentEntityV
offset2 = pos; offset2 = pos;
} }
stack.translate(pos.x - posX, (offset1.y + offset2.y) / 2.0D - posY, pos.z - posZ); stack.translate((float) (pos.x - posX), (float) ((offset1.y + offset2.y) / 2.0D - posY), (float) (pos.z - posZ));
Vec3 vec = offset2.add(-offset1.x, -offset1.y, -offset1.z); Vec3 vec = offset2.add(-offset1.x, -offset1.y, -offset1.z);
if (vec.length() != 0.0D) { if (vec.length() != 0.0D) {
vec = vec.normalize(); vec = vec.normalize();
@ -175,9 +148,9 @@ public class MinecartVisual<T extends AbstractMinecart> extends ComponentEntityV
} }
} }
stack.translate(0.0D, 0.375D, 0.0D); stack.translate(0.0F, 0.375F, 0.0F);
stack.mulPose(Axis.YP.rotationDegrees(180 - yaw)); stack.rotateY((180 - yaw) * Mth.DEG_TO_RAD);
stack.mulPose(Axis.ZP.rotationDegrees(-pitch)); stack.rotateZ(-pitch * Mth.DEG_TO_RAD);
float hurtTime = entity.getHurtTime() - partialTick; float hurtTime = entity.getHurtTime() - partialTick;
float damage = entity.getDamage() - partialTick; float damage = entity.getDamage() - partialTick;
@ -187,40 +160,44 @@ public class MinecartVisual<T extends AbstractMinecart> extends ComponentEntityV
} }
if (hurtTime > 0) { if (hurtTime > 0) {
stack.mulPose(Axis.XP.rotationDegrees(Mth.sin(hurtTime) * hurtTime * damage / 10.0F * (float) entity.getHurtDir())); stack.rotateX((Mth.sin(hurtTime) * hurtTime * damage / 10.0F * (float) entity.getHurtDir()) * Mth.DEG_TO_RAD);
} }
int displayOffset = entity.getDisplayOffset();
if (contents != null) { if (contents != null) {
stack.pushPose(); int displayOffset = entity.getDisplayOffset();
stack.pushMatrix();
stack.scale(0.75F, 0.75F, 0.75F); stack.scale(0.75F, 0.75F, 0.75F);
stack.translate(-0.5F, (float) (displayOffset - 8) / 16, 0.5F); stack.translate(-0.5F, (float) (displayOffset - 8) / 16, 0.5F);
stack.mulPose(Axis.YP.rotationDegrees(90)); stack.rotateY(90 * Mth.DEG_TO_RAD);
updateContents(contents, stack, partialTick); updateContents(contents, stack, partialTick);
stack.popPose(); stack.popMatrix();
} }
stack.scale(-1.0F, -1.0F, 1.0F); stack.scale(-1.0F, -1.0F, 1.0F);
body.setTransform(stack) instances.updateInstances(stack);
.setChanged();
// TODO: Use LightUpdatedVisual/ShaderLightVisual if possible. // TODO: Use LightUpdatedVisual/ShaderLightVisual if possible.
updateLight(partialTick); updateLight(partialTick);
} }
protected void updateContents(TransformedInstance contents, PoseStack stack, float partialTick) { protected void updateContents(TransformedInstance contents, Matrix4f pose, float partialTick) {
contents.setTransform(stack) contents.setTransform(pose)
.setChanged(); .setChanged();
} }
public void updateLight(float partialTick) { public void updateLight(float partialTick) {
relight(partialTick, body, contents); int packedLight = computePackedLight(partialTick);
instances.traverse(instance -> {
instance.light(packedLight)
.setChanged();
});
FlatLit.relight(packedLight, contents);
} }
@Override @Override
protected void _delete() { protected void _delete() {
super._delete(); super._delete();
body.delete(); instances.delete();
if (contents != null) { if (contents != null) {
contents.delete(); contents.delete();
} }

View File

@ -1,9 +1,10 @@
package dev.engine_room.flywheel.vanilla; package dev.engine_room.flywheel.vanilla;
import com.mojang.blaze3d.vertex.PoseStack; import org.joml.Matrix4f;
import dev.engine_room.flywheel.api.visualization.VisualizationContext; import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import dev.engine_room.flywheel.lib.instance.TransformedInstance; import dev.engine_room.flywheel.lib.instance.TransformedInstance;
import net.minecraft.client.model.geom.ModelLayers;
import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.entity.vehicle.MinecartTNT; import net.minecraft.world.entity.vehicle.MinecartTNT;
@ -12,11 +13,11 @@ public class TntMinecartVisual<T extends MinecartTNT> extends MinecartVisual<T>
private static final int WHITE_OVERLAY = OverlayTexture.pack(OverlayTexture.u(1.0F), 10); private static final int WHITE_OVERLAY = OverlayTexture.pack(OverlayTexture.u(1.0F), 10);
public TntMinecartVisual(VisualizationContext ctx, T entity, float partialTick) { public TntMinecartVisual(VisualizationContext ctx, T entity, float partialTick) {
super(ctx, entity, partialTick, TNT_BODY_MODEL); super(ctx, entity, partialTick, ModelLayers.TNT_MINECART);
} }
@Override @Override
protected void updateContents(TransformedInstance contents, PoseStack stack, float partialTick) { protected void updateContents(TransformedInstance contents, Matrix4f pose, float partialTick) {
int fuseTime = entity.getFuse(); int fuseTime = entity.getFuse();
if (fuseTime > -1 && (float) fuseTime - partialTick + 1.0F < 10.0F) { if (fuseTime > -1 && (float) fuseTime - partialTick + 1.0F < 10.0F) {
float f = 1.0F - ((float) fuseTime - partialTick + 1.0F) / 10.0F; float f = 1.0F - ((float) fuseTime - partialTick + 1.0F) / 10.0F;
@ -24,7 +25,7 @@ public class TntMinecartVisual<T extends MinecartTNT> extends MinecartVisual<T>
f *= f; f *= f;
f *= f; f *= f;
float scale = 1.0F + f * 0.3F; float scale = 1.0F + f * 0.3F;
stack.scale(scale, scale, scale); pose.scale(scale);
} }
int overlay; int overlay;
@ -34,7 +35,7 @@ public class TntMinecartVisual<T extends MinecartTNT> extends MinecartVisual<T>
overlay = OverlayTexture.NO_OVERLAY; overlay = OverlayTexture.NO_OVERLAY;
} }
contents.setTransform(stack) contents.setTransform(pose)
.overlay(overlay) .overlay(overlay)
.setChanged(); .setChanged();
} }

View File

@ -3,6 +3,7 @@ package dev.engine_room.flywheel.vanilla;
import static dev.engine_room.flywheel.lib.visualization.SimpleBlockEntityVisualizer.builder; import static dev.engine_room.flywheel.lib.visualization.SimpleBlockEntityVisualizer.builder;
import static dev.engine_room.flywheel.lib.visualization.SimpleEntityVisualizer.builder; import static dev.engine_room.flywheel.lib.visualization.SimpleEntityVisualizer.builder;
import net.minecraft.client.model.geom.ModelLayers;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
@ -47,27 +48,27 @@ public class VanillaVisuals {
.apply(); .apply();
builder(EntityType.CHEST_MINECART) builder(EntityType.CHEST_MINECART)
.factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, MinecartVisual.CHEST_BODY_MODEL)) .factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, ModelLayers.CHEST_MINECART))
.skipVanillaRender(MinecartVisual::shouldSkipRender) .skipVanillaRender(MinecartVisual::shouldSkipRender)
.apply(); .apply();
builder(EntityType.COMMAND_BLOCK_MINECART) builder(EntityType.COMMAND_BLOCK_MINECART)
.factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, MinecartVisual.COMMAND_BLOCK_BODY_MODEL)) .factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, ModelLayers.COMMAND_BLOCK_MINECART))
.skipVanillaRender(MinecartVisual::shouldSkipRender) .skipVanillaRender(MinecartVisual::shouldSkipRender)
.apply(); .apply();
builder(EntityType.FURNACE_MINECART) builder(EntityType.FURNACE_MINECART)
.factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, MinecartVisual.FURNACE_BODY_MODEL)) .factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, ModelLayers.FURNACE_MINECART))
.skipVanillaRender(MinecartVisual::shouldSkipRender) .skipVanillaRender(MinecartVisual::shouldSkipRender)
.apply(); .apply();
builder(EntityType.HOPPER_MINECART) builder(EntityType.HOPPER_MINECART)
.factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, MinecartVisual.HOPPER_BODY_MODEL)) .factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, ModelLayers.HOPPER_MINECART))
.skipVanillaRender(MinecartVisual::shouldSkipRender) .skipVanillaRender(MinecartVisual::shouldSkipRender)
.apply(); .apply();
builder(EntityType.MINECART) builder(EntityType.MINECART)
.factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, MinecartVisual.STANDARD_BODY_MODEL)) .factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, ModelLayers.MINECART))
.skipVanillaRender(MinecartVisual::shouldSkipRender) .skipVanillaRender(MinecartVisual::shouldSkipRender)
.apply(); .apply();
builder(EntityType.SPAWNER_MINECART) builder(EntityType.SPAWNER_MINECART)
.factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, MinecartVisual.SPAWNER_BODY_MODEL)) .factory((ctx, entity, partialTick) -> new MinecartVisual<>(ctx, entity, partialTick, ModelLayers.SPAWNER_MINECART))
.skipVanillaRender(MinecartVisual::shouldSkipRender) .skipVanillaRender(MinecartVisual::shouldSkipRender)
.apply(); .apply();
builder(EntityType.TNT_MINECART) builder(EntityType.TNT_MINECART)