Overridden overrides

- Only instance items if their *base* baked model has no overrides
- ItemRenderer#getModel applies overrides internally, so we have to go
  directly to the ItemModelShaper
- Don't filter the results of ClientLevel#entitiesForRendering, instead
  do an early exit in LevelRenderer#renderEntity
  - Avoids allocating a potentially massive list
  - Only need to loop over the entity list once
  - Visible entity counter is fixed
  - Would be nice to continue out of an iteration to avoid other
    unnecessary checks in the render loop, but I don't think there's a
    way to do that with mixin
- Use a persistent rotation quat in InstanceTree to avoid allocations
- Only call setChanged when updating instances in CowVisual, saves a ton
  of atomic overhead
This commit is contained in:
Jozufozu 2024-04-13 13:19:47 -07:00
parent 08b09f8a3c
commit 5df7b09ecb
7 changed files with 35 additions and 58 deletions

View file

@ -1,32 +0,0 @@
package com.jozufozu.flywheel.impl.mixin;
import java.util.ArrayList;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.google.common.collect.Lists;
import com.jozufozu.flywheel.api.visualization.VisualizationManager;
import com.jozufozu.flywheel.impl.visualization.VisualizationHelper;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.world.entity.Entity;
@Mixin(ClientLevel.class)
abstract class ClientLevelMixin {
@Inject(method = "entitiesForRendering()Ljava/lang/Iterable;", at = @At("RETURN"), cancellable = true)
private void flywheel$filterEntities(CallbackInfoReturnable<Iterable<Entity>> cir) {
if (!VisualizationManager.supportsVisualization((ClientLevel) (Object) this)) {
return;
}
Iterable<Entity> entities = cir.getReturnValue();
ArrayList<Entity> filtered = Lists.newArrayList(entities);
filtered.removeIf(VisualizationHelper::shouldSkipRender);
cir.setReturnValue(filtered);
}
}

View file

@ -18,7 +18,9 @@ import com.jozufozu.flywheel.api.event.BeginFrameEvent;
import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent;
import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.event.RenderStageEvent;
import com.jozufozu.flywheel.api.visualization.VisualizationManager;
import com.jozufozu.flywheel.impl.event.RenderContextImpl;
import com.jozufozu.flywheel.impl.visualization.VisualizationHelper;
import com.jozufozu.flywheel.impl.visualization.VisualizationManagerImpl;
import com.mojang.blaze3d.vertex.PoseStack;
@ -28,8 +30,10 @@ import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderBuffers;
import net.minecraft.server.level.BlockDestructionProgress;
import net.minecraft.world.entity.Entity;
import net.minecraftforge.common.MinecraftForge;
@Mixin(value = LevelRenderer.class, priority = 1001) // Higher priority to go after Sodium
@ -79,6 +83,14 @@ abstract class LevelRendererMixin {
}
}
// ENTITY CANCELLING
@Inject(method = "renderEntity", at = @At("HEAD"), cancellable = true)
private void flywheel$decideNotToRenderEntity(Entity pEntity, double pCamX, double pCamY, double pCamZ, float pPartialTick, PoseStack pPoseStack, MultiBufferSource pBufferSource, CallbackInfo ci) {
if (VisualizationManager.supportsVisualization(pEntity.level()) && VisualizationHelper.shouldSkipRender(pEntity)) {
ci.cancel();
}
}
// STAGE DISPATCHING
@Unique

View file

@ -39,6 +39,7 @@ public class InstanceTree {
@Nullable
public TransformedInstance instance;
private final Quaternionf rotation = new Quaternionf();
private final Entry entry;
private final PartPose initialPose;
@ -136,7 +137,7 @@ public class InstanceTree {
void accept(T t, int i, int j);
}
public void render(PoseStack pPoseStack) {
public void updateInstances(PoseStack pPoseStack) {
if (this.visible) {
pPoseStack.pushPose();
this.translateAndRotate(pPoseStack);
@ -146,7 +147,7 @@ public class InstanceTree {
}
for (InstanceTree modelpart : this.children.values()) {
modelpart.render(pPoseStack);
modelpart.updateInstances(pPoseStack);
}
pPoseStack.popPose();
@ -156,7 +157,7 @@ public class InstanceTree {
public void translateAndRotate(PoseStack pPoseStack) {
pPoseStack.translate(this.x / 16.0F, this.y / 16.0F, this.z / 16.0F);
if (this.xRot != 0.0F || this.yRot != 0.0F || this.zRot != 0.0F) {
pPoseStack.mulPose((new Quaternionf()).rotationZYX(this.zRot, this.yRot, this.xRot));
pPoseStack.mulPose(rotation.rotationZYX(this.zRot, this.yRot, this.xRot));
}
if (this.xScale != 1.0F || this.yScale != 1.0F || this.zScale != 1.0F) {

View file

@ -22,24 +22,24 @@ public abstract class AgeableListComponent {
}
pPoseStack.translate(0.0F, this.config.babyYHeadOffset / 16.0F, this.config.babyZHeadOffset / 16.0F);
for (InstanceTree p_102081_ : this.headParts()) {
p_102081_.render(pPoseStack);
for (InstanceTree headPart : this.headParts()) {
headPart.updateInstances(pPoseStack);
}
pPoseStack.popPose();
pPoseStack.pushPose();
float f1 = 1.0F / this.config.babyBodyScale;
pPoseStack.scale(f1, f1, f1);
pPoseStack.translate(0.0F, this.config.bodyYOffset / 16.0F, 0.0F);
for (InstanceTree p_102071_ : this.bodyParts()) {
p_102071_.render(pPoseStack);
for (InstanceTree bodyPart : this.bodyParts()) {
bodyPart.updateInstances(pPoseStack);
}
pPoseStack.popPose();
} else {
for (InstanceTree p_102061_ : this.headParts()) {
p_102061_.render(pPoseStack);
for (InstanceTree headPart : this.headParts()) {
headPart.updateInstances(pPoseStack);
}
for (InstanceTree p_102051_ : this.bodyParts()) {
p_102051_.render(pPoseStack);
for (InstanceTree bodyPart : this.bodyParts()) {
bodyPart.updateInstances(pPoseStack);
}
}

View file

@ -65,7 +65,7 @@ public class CowVisual extends SimpleEntityVisual<Cow> {
cowQuadrupedComponent.root.walkInstances(overlay, light, (i, o, l) -> {
i.setOverlay(o);
i.light(l);
i.setChanged();
// We'll #setChanged in the
});
stack.setIdentity();

View file

@ -18,6 +18,7 @@ import com.mojang.math.Axis;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.block.model.ItemOverrides;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.MultiPartBakedModel;
import net.minecraft.client.resources.model.SimpleBakedModel;
@ -48,9 +49,7 @@ public class ItemVisual extends SimpleEntityVisual<ItemEntity> {
super(ctx, entity);
var item = entity.getItem();
model = Minecraft.getInstance()
.getItemRenderer()
.getModel(item, entity.level(), null, entity.getId());
model = getModel(item);
isSupported = isSupported(model);
@ -61,11 +60,14 @@ public class ItemVisual extends SimpleEntityVisual<ItemEntity> {
}
public static boolean isSupported(ItemEntity entity) {
var model = Minecraft.getInstance()
.getItemRenderer()
.getModel(entity.getItem(), entity.level(), null, entity.getId());
return isSupported(getModel(entity.getItem()));
}
return isSupported(model);
public static BakedModel getModel(ItemStack stack) {
return Minecraft.getInstance()
.getItemRenderer()
.getItemModelShaper()
.getItemModel(stack);
}
public static boolean isSupported(BakedModel model) {
@ -73,9 +75,7 @@ public class ItemVisual extends SimpleEntityVisual<ItemEntity> {
return false;
}
if (!model.getOverrides()
.getOverrides()
.isEmpty()) {
if (model.getOverrides() != ItemOverrides.EMPTY) {
return false;
}
@ -110,7 +110,6 @@ public class ItemVisual extends SimpleEntityVisual<ItemEntity> {
.translate(getVisualPosition(ctx.partialTick()));
instances.resetCount();
pPoseStack.pushPose();
ItemStack itemstack = entity.getItem();
int i = itemstack.isEmpty() ? 187 : Item.getId(itemstack.getItem()) + itemstack.getDamageValue();
var random = RANDOM.get();
@ -158,7 +157,6 @@ public class ItemVisual extends SimpleEntityVisual<ItemEntity> {
}
}
pPoseStack.popPose();
instances.discardExtra();
}
@ -199,7 +197,6 @@ public class ItemVisual extends SimpleEntityVisual<ItemEntity> {
}
public record ItemKey(ItemStack stack, BakedModel model) {
@Override
public boolean equals(Object o) {
if (this == o) {

View file

@ -7,7 +7,6 @@
"client": [
"BlockEntityTypeMixin",
"ClientChunkCacheMixin",
"ClientLevelMixin",
"EntityTypeMixin",
"LevelMixin",
"LevelRendererMixin",