Port renderer api and indigo to 26.2 (#5406)

* Ported renderer api and indigo to 26.2-snapshot-8

This commit updates the `fabric-renderer-api-v1` and
`fabric-renderer-indigo` modules to 26.2-snapshot-8. The code was
changed to remove all usages of `MultiBufferSource`, and use the new
`RenderTypeFeatureRenderer` system instead.

* Fixed coding style and javadoc

* Replaced a static assignment with a ScopedValue

* Implemented outline rendertype for models & some cleanup

* Fixes, cleanup, optimizations

* Fix block breaking and checkstyle

* Require renderers to implement extended block model feature renderer

* refactor!: move submits to `submit` sub-package

---------

Co-authored-by: PepperCode1 <44146161+PepperCode1@users.noreply.github.com>
Co-authored-by: sylv256 <contact@sylv.gay>
This commit is contained in:
Rigner 2026-06-10 12:31:23 +02:00 committed by GitHub
parent 3568f873c4
commit e73ab60dfd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 861 additions and 641 deletions

View file

@ -25,8 +25,8 @@ import net.minecraft.client.renderer.block.BlockQuadOutput;
import net.minecraft.client.renderer.block.ModelBlockRenderer;
import net.minecraft.client.renderer.block.dispatch.BlockStateModel;
import net.minecraft.client.renderer.chunk.SectionCompiler;
import net.minecraft.client.renderer.feature.BlockModelFeatureRenderer;
import net.minecraft.client.renderer.feature.ItemFeatureRenderer;
import net.minecraft.client.renderer.feature.FeatureRenderDispatcher;
import net.minecraft.client.renderer.feature.FeatureRenderer;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.state.BlockState;
@ -36,7 +36,8 @@ import net.fabricmc.fabric.api.client.renderer.v1.mesh.MutableMesh;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.MutableQuadView;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.client.renderer.v1.render.AltModelBlockRenderer;
import net.fabricmc.fabric.api.client.renderer.v1.render.FabricSubmitNodeCollection;
import net.fabricmc.fabric.api.client.renderer.v1.render.submit.ExtendedBlockModelSubmit;
import net.fabricmc.fabric.api.client.renderer.v1.render.submit.ExtendedItemSubmit;
import net.fabricmc.fabric.impl.client.renderer.RendererManager;
/**
@ -54,9 +55,9 @@ import net.fabricmc.fabric.impl.client.renderer.RendererManager;
* {@link AltModelBlockRenderer#tesselateBlock(QuadEmitter, float, float, float, BlockAndTintGetter, BlockPos, BlockState, BlockStateModel, long)},
* respectively, instead.
*
* <p>Renderers must patch {@link ItemFeatureRenderer} to support
* {@link FabricSubmitNodeCollection#getExtendedItemSubmits()}. {@link BlockModelFeatureRenderer} is automatically patched
* to support {@link FabricSubmitNodeCollection#getExtendedBlockModelSubmits()} and {@link BlockStateModel#emitQuads}.
* <p>Renderers must implement {@link FeatureRenderer}s to support {@link ExtendedBlockModelSubmit}
* and {@link ExtendedItemSubmit}. This is typically done by adding them to
* {@link FeatureRenderDispatcher}'s map with a mixin.
*/
public interface Renderer {
/**

View file

@ -59,7 +59,22 @@ public interface FabricOrderedSubmitNodeCollector {
}
/**
* Alternative to {@link OrderedSubmitNodeCollector#submitItem(PoseStack, ItemDisplayContext, int, int, int, int[], List, ItemStackRenderState.FoilType)} that also accepts a {@link MeshView}.
* Alternative to
* {@link OrderedSubmitNodeCollector#submitBreakingBlockModel(PoseStack, List, int)} that also
* accepts a {@link Mesh}.
*
* @param poseStack the pose stack
* @param parts the vanilla {@linkplain BlockStateModelPart parts}
* @param mesh the mesh
* @param progress the breaking progress
*/
default void submitBreakingBlockModel(PoseStack poseStack, List<BlockStateModelPart> parts, Mesh mesh, int progress) {
((OrderedSubmitNodeCollector) this).submitBreakingBlockModel(poseStack, parts, progress);
}
/**
* Alternative to {@link OrderedSubmitNodeCollector#submitItem(PoseStack, ItemDisplayContext, int, int, int, int[], List, ItemStackRenderState.FoilType)}
* that also accepts a {@link MeshView}.
*
* @param poseStack the pose stack
* @param displayContext the item display context

View file

@ -1,72 +0,0 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.api.client.renderer.v1.render;
import java.util.List;
import java.util.function.Function;
import com.mojang.blaze3d.vertex.PoseStack;
import org.jspecify.annotations.Nullable;
import net.minecraft.client.renderer.SubmitNodeCollection;
import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart;
import net.minecraft.client.renderer.chunk.ChunkSectionLayer;
import net.minecraft.client.renderer.feature.BlockModelFeatureRenderer;
import net.minecraft.client.renderer.feature.ItemFeatureRenderer;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.renderer.rendertype.RenderType;
import net.minecraft.client.resources.model.geometry.BakedQuad;
import net.minecraft.world.item.ItemDisplayContext;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.Mesh;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.MeshView;
/**
* Note: This interface is automatically implemented on {@link SubmitNodeCollection} via Mixin and interface injection.
*/
public interface FabricSubmitNodeCollection {
/**
* @return {@linkplain ExtendedBlockModelSubmit extended block model submits} in this
* {@link SubmitNodeCollection}.
*/
default List<ExtendedBlockModelSubmit> getExtendedBlockModelSubmits() {
throw new UnsupportedOperationException("Implemented via Mixin.");
}
/**
* @return {@linkplain ExtendedItemSubmit extended item submits} in this
* {@link SubmitNodeCollection}.
*/
default List<ExtendedItemSubmit> getExtendedItemSubmits() {
throw new UnsupportedOperationException("Implemented via Mixin.");
}
// CHECKSTYLE:OFF MatchXpath
/**
* An alternative to {@link BlockModelFeatureRenderer.Submit} that accepts a {@link Mesh}.
*/
record ExtendedBlockModelSubmit(PoseStack.Pose pose, Function<ChunkSectionLayer, RenderType> renderTypeFunction, boolean translucent, List<BlockStateModelPart> modelParts, @Nullable Mesh mesh, int[] tintLayers, int lightCoords, int overlayCoords, int outlineColor) {
}
/**
* An alternative to {@link ItemFeatureRenderer.Submit} that accepts a {@link MeshView}.
*/
record ExtendedItemSubmit(PoseStack.Pose pose, ItemDisplayContext displayContext, int lightCoords, int overlayCoords, int outlineColor, int[] tintLayers, List<BakedQuad> quads, MeshView mesh, ItemStackRenderState.FoilType foilType) {
}
// CHECKSTYLE:ON MatchXpath
}

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.api.client.renderer.v1.render.submit;
import java.util.List;
import java.util.function.Function;
import com.mojang.blaze3d.vertex.PoseStack;
import org.jspecify.annotations.Nullable;
import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart;
import net.minecraft.client.renderer.chunk.ChunkSectionLayer;
import net.minecraft.client.renderer.feature.BlockModelFeatureRenderer;
import net.minecraft.client.renderer.feature.FeatureRendererType;
import net.minecraft.client.renderer.feature.submit.TranslucentSubmit;
import net.minecraft.client.renderer.rendertype.RenderType;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.Mesh;
/**
* An alternative to {@link BlockModelFeatureRenderer.Submit} that optionally accepts a {@link Mesh}.
*/
//CHECKSTYLE.OFF: MatchXpath
public record ExtendedBlockModelSubmit(PoseStack.Pose pose,
Function<ChunkSectionLayer, @Nullable RenderType> renderTypeFunction,
List<BlockStateModelPart> modelParts, @Nullable Mesh mesh,
int[] tintLayers, int lightCoords, int overlayCoords,
int tintColor, PoseStack.@Nullable Pose sheetedDecalPose) implements TranslucentSubmit {
//CHECKSTYLE.ON: MatchXpath
public static final FeatureRendererType<ExtendedBlockModelSubmit> TYPE = FeatureRendererType.create("Extended Block Model");
@Override
public float distanceToCameraSq() {
return TranslucentSubmit.computeDistanceToCameraSq(pose.pose(), 0.5F, 0.5F, 0.5F);
}
@Override
public FeatureRendererType<? extends TranslucentSubmit> featureType() {
return TYPE;
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.api.client.renderer.v1.render.submit;
import java.util.List;
import java.util.function.Consumer;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.renderer.feature.FeatureRendererType;
import net.minecraft.client.renderer.feature.ItemFeatureRenderer;
import net.minecraft.client.renderer.feature.submit.TranslucentSubmit;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.resources.model.geometry.BakedQuad;
import net.minecraft.world.item.ItemDisplayContext;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.MeshView;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadView;
/**
* An alternative to {@link ItemFeatureRenderer.Submit} that accepts a {@link MeshView}.
*/
//CHECKSTYLE.OFF: MatchXpath
public record ExtendedItemSubmit(PoseStack.Pose pose, ItemDisplayContext displayContext,
int lightCoords, int overlayCoords, int outlineColor,
int[] tintLayers, List<BakedQuad> quads, MeshView mesh,
ItemStackRenderState.FoilType foilType) implements TranslucentSubmit {
//CHECKSTYLE.ON: MatchXpath
public static final FeatureRendererType<ExtendedItemSubmit> TYPE = FeatureRendererType.create("Extended Item");
public boolean hasTranslucency() {
for (BakedQuad quad : quads()) {
if (quad.materialInfo().itemRenderType().hasBlending()) {
return true;
}
}
var quadInspector = new Consumer<QuadView>() {
private boolean translucent = false;
@Override
public void accept(QuadView quad) {
if (quad.itemRenderType().hasBlending()) {
translucent = true;
}
}
};
mesh.forEach(quadInspector);
return quadInspector.translucent;
}
@Override
public float distanceToCameraSq() {
return TranslucentSubmit.computeDistanceToCameraSq(pose.pose());
}
@Override
public FeatureRendererType<? extends TranslucentSubmit> featureType() {
return TYPE;
}
}

View file

@ -1,77 +0,0 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.impl.client.renderer;
import com.mojang.blaze3d.vertex.VertexConsumer;
import org.jspecify.annotations.Nullable;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.OutlineBufferSource;
import net.minecraft.client.renderer.rendertype.RenderType;
public class BlockModelBufferCache {
private final MultiBufferSource.BufferSource bufferSource;
private final OutlineBufferSource outlineBufferSource;
private int outlineColor;
@Nullable
private RenderType lastRenderType;
@Nullable
private VertexConsumer lastBuffer;
@Nullable
private VertexConsumer lastOutlineBuffer;
public BlockModelBufferCache(MultiBufferSource.BufferSource bufferSource, OutlineBufferSource outlineBufferSource) {
this.bufferSource = bufferSource;
this.outlineBufferSource = outlineBufferSource;
}
public void outlineColor(int outlineColor) {
this.outlineColor = outlineColor;
lastRenderType = null;
}
public VertexConsumer getBuffer(RenderType renderType) {
if (renderType != lastRenderType) {
update(renderType);
}
return lastBuffer;
}
@Nullable
public VertexConsumer getOutlineBuffer(RenderType renderType) {
if (renderType != lastRenderType) {
update(renderType);
}
return lastOutlineBuffer;
}
private void update(RenderType renderType) {
lastRenderType = renderType;
lastBuffer = bufferSource.getBuffer(renderType);
if (outlineColor != 0) {
outlineBufferSource.setColor(outlineColor);
lastOutlineBuffer = outlineBufferSource.getBuffer(renderType);
} else {
lastOutlineBuffer = null;
}
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.impl.client.renderer;
import java.util.function.Consumer;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.MutableQuadView;
public abstract class MovingBlockQuadConsumer implements Consumer<MutableQuadView> {
protected int outlineColor;
public void outlineColor(int outlineColor) {
this.outlineColor = outlineColor;
}
}

View file

@ -1,80 +0,0 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.impl.client.renderer;
import java.util.function.Consumer;
import java.util.function.Function;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.chunk.ChunkSectionLayer;
import net.minecraft.client.renderer.rendertype.RenderType;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.util.LightCoordsUtil;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.MutableQuadView;
// Workaround for mixin not allowing referencing members of anonymous classes defined within mixins.
// Once that is fixed, this class should be inlined.
public final class QuadConsumers {
private QuadConsumers() {
}
public static class BlockModel implements Consumer<MutableQuadView> {
public int[] tintLayers;
public int lightCoords;
public int overlayCoords;
public PoseStack.Pose pose;
public Function<ChunkSectionLayer, RenderType> renderTypeFunction;
public BlockModelBufferCache bufferCache;
@Override
public void accept(MutableQuadView quad) {
if (quad.emissive()) {
quad.lightmap(LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT);
} else {
quad.minLightmap(lightCoords);
}
int tintIndex = quad.tintIndex();
if (tintIndex != -1 && tintIndex < tintLayers.length) {
quad.multiplyColor(tintLayers[tintIndex]);
}
RenderType renderType = renderTypeFunction.apply(quad.chunkLayer());
quad.buffer(overlayCoords, pose, bufferCache.getBuffer(renderType));
VertexConsumer outlineBuffer = bufferCache.getOutlineBuffer(renderType);
if (outlineBuffer != null) {
quad.buffer(overlayCoords, pose, outlineBuffer);
}
}
}
public static class BreakingBlockModel implements Consumer<MutableQuadView> {
public PoseStack.Pose pose;
public VertexConsumer buffer;
@Override
public void accept(MutableQuadView quad) {
quad.lightmap(LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT);
quad.buffer(OverlayTexture.NO_OVERLAY, pose, buffer);
}
}
}

View file

@ -20,18 +20,20 @@ import java.util.function.Predicate;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
import org.jspecify.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart;
import net.minecraft.client.renderer.block.dispatch.ModelState;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.SimpleModelWrapper;
@ -53,8 +55,23 @@ abstract class SimpleModelWrapperMixin implements BlockStateModelPart {
@Final
private boolean useAmbientOcclusion;
@Inject(method = "bake", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/geometry/QuadCollection;getAll()Ljava/util/List;"))
private static void analyzeMesh(final ModelBaker modelBakery, final Identifier location, final ModelState state, CallbackInfoReturnable<BlockStateModelPart> cir, @Local(name = "geometry") QuadCollection geometry, @Local(name = "forbiddenSprites") LocalRef<Multimap<Identifier, Identifier>> forbiddenSpritesRef) {
@Unique
private static final ScopedValue<ModelBaker> MODEL_BAKERY = ScopedValue.newInstance();
@WrapOperation(method = "bake", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/SimpleModelWrapper;findNonBlockSprites(Lnet/minecraft/client/resources/model/geometry/QuadCollection;)Lcom/google/common/collect/Multimap;"))
private static @Nullable Multimap<Identifier, Identifier> storeModelBakery(QuadCollection geometry, Operation<Multimap<Identifier, Identifier>> original, @Local(name = "modelBakery") ModelBaker modelBakery) {
return ScopedValue.where(MODEL_BAKERY, modelBakery).call(() -> original.call(geometry));
}
@Inject(method = "findNonBlockSprites", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/geometry/QuadCollection;getAll()Ljava/util/List;"))
private static void analyzeMesh(QuadCollection geometry, CallbackInfoReturnable<Multimap<Identifier, Identifier>> cir, @Local(name = "forbiddenSprites") LocalRef<Multimap<Identifier, Identifier>> forbiddenSpritesRef) {
// This can also be called from ModelBakery.MissingModels, but it's maybe not necessary to hook there?
if (!MODEL_BAKERY.isBound()) {
return;
}
ModelBaker modelBakery = MODEL_BAKERY.get();
if (geometry instanceof MeshQuadCollection meshQuadCollection) {
meshQuadCollection.getMesh().forEach(quad -> {
if (quad.atlas() != QuadAtlas.BLOCK) {

View file

@ -1,110 +0,0 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.client.renderer.block.render;
import java.util.function.Function;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.QuadInstance;
import com.mojang.blaze3d.vertex.VertexConsumer;
import org.jspecify.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.client.renderer.SubmitNodeCollection;
import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart;
import net.minecraft.client.renderer.chunk.ChunkSectionLayer;
import net.minecraft.client.renderer.feature.BlockModelFeatureRenderer;
import net.minecraft.client.renderer.feature.FeatureFrameContext;
import net.minecraft.client.renderer.rendertype.RenderType;
import net.minecraft.client.resources.model.geometry.BakedQuad;
import net.minecraft.core.Direction;
import net.fabricmc.fabric.api.client.renderer.v1.Renderer;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.client.renderer.v1.render.FabricSubmitNodeCollection;
import net.fabricmc.fabric.impl.client.renderer.BlockModelBufferCache;
import net.fabricmc.fabric.impl.client.renderer.QuadConsumers;
@Mixin(BlockModelFeatureRenderer.class)
abstract class BlockModelFeatureRendererMixin {
@Shadow
@Final
private static Direction[] DIRECTIONS;
@Shadow
@Final
private QuadInstance quadInstance;
@Shadow
private static void putQuad(PoseStack.Pose pose, BakedQuad quad, QuadInstance instance, int[] tintLayers, VertexConsumer buffer, @Nullable VertexConsumer outlineBuffer) {
}
@Unique
private static void putPartQuads(BlockStateModelPart part, PoseStack.Pose pose, QuadInstance quadInstance, int[] tintLayers, Function<ChunkSectionLayer, RenderType> renderTypeFunction, BlockModelBufferCache bufferCache) {
for (Direction direction : DIRECTIONS) {
for (BakedQuad quad : part.getQuads(direction)) {
RenderType renderType = renderTypeFunction.apply(quad.materialInfo().layer());
putQuad(pose, quad, quadInstance, tintLayers, bufferCache.getBuffer(renderType), bufferCache.getOutlineBuffer(renderType));
}
}
for (BakedQuad quad : part.getQuads(null)) {
RenderType renderType = renderTypeFunction.apply(quad.materialInfo().layer());
putQuad(pose, quad, quadInstance, tintLayers, bufferCache.getBuffer(renderType), bufferCache.getOutlineBuffer(renderType));
}
}
@Inject(method = "renderModels", at = @At("RETURN"))
private void onReturnRenderModels(SubmitNodeCollection nodeCollection, FeatureFrameContext context, boolean translucent, CallbackInfo ci) {
BlockModelBufferCache bufferCache = new BlockModelBufferCache((net.minecraft.client.renderer.MultiBufferSource.BufferSource) context.bufferSource(), context.outlineBufferSource());
QuadConsumers.BlockModel quadConsumer = new QuadConsumers.BlockModel();
QuadEmitter output = Renderer.get().quadEmitter(quadConsumer);
for (FabricSubmitNodeCollection.ExtendedBlockModelSubmit submit : nodeCollection.getExtendedBlockModelSubmits()) {
if (submit.translucent() == translucent) {
PoseStack.Pose pose = submit.pose();
int[] tintLayers = submit.tintLayers();
Function<ChunkSectionLayer, RenderType> renderTypeFunction = submit.renderTypeFunction();
bufferCache.outlineColor(submit.outlineColor());
quadInstance.setLightCoords(submit.lightCoords());
quadInstance.setOverlayCoords(submit.overlayCoords());
for (BlockStateModelPart part : submit.modelParts()) {
putPartQuads(part, pose, quadInstance, tintLayers, renderTypeFunction, bufferCache);
}
if (submit.mesh() != null) {
quadConsumer.tintLayers = tintLayers;
quadConsumer.lightCoords = submit.lightCoords();
quadConsumer.overlayCoords = submit.overlayCoords();
quadConsumer.pose = pose;
quadConsumer.renderTypeFunction = renderTypeFunction;
quadConsumer.bufferCache = bufferCache;
submit.mesh().outputTo(output);
}
}
}
}
}

View file

@ -0,0 +1,60 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.client.renderer.block.render;
import java.util.List;
import com.llamalad7.mixinextras.sugar.Local;
import com.llamalad7.mixinextras.sugar.Share;
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
import com.mojang.blaze3d.vertex.PoseStack;
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.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.SubmitNodeCollector;
import net.minecraft.client.renderer.block.BlockAndTintGetter;
import net.minecraft.client.renderer.block.dispatch.BlockStateModel;
import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart;
import net.minecraft.client.renderer.state.level.BlockBreakingRenderState;
import net.minecraft.util.RandomSource;
import net.fabricmc.fabric.api.client.renderer.v1.Renderer;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.MutableMesh;
@Mixin(LevelRenderer.class)
abstract class LevelRendererMixin {
@Inject(method = "submitBlockDestroyAnimation(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/state/level/LevelRenderState;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/RandomSource;createThreadLocalInstance()Lnet/minecraft/util/RandomSource;"))
private void beforeCreateRandom(CallbackInfo ci, @Share("mutableMesh") LocalRef<MutableMesh> mutableMesh) {
mutableMesh.set(Renderer.get().mutableMesh());
}
@Redirect(method = "submitBlockDestroyAnimation(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/state/level/LevelRenderState;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/block/dispatch/BlockStateModel;collectParts(Lnet/minecraft/util/RandomSource;Ljava/util/List;)V"))
private void cancelCollectParts(BlockStateModel model, RandomSource random, List<BlockStateModelPart> output) {
}
@Redirect(method = "submitBlockDestroyAnimation(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/state/level/LevelRenderState;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/SubmitNodeCollector;submitBreakingBlockModel(Lcom/mojang/blaze3d/vertex/PoseStack;Ljava/util/List;I)V"))
private void submitBreakingBlockModelProxy(SubmitNodeCollector submitNodeCollector, PoseStack poseStack, List<BlockStateModelPart> parts, int progress, @Local(name = "random") RandomSource random, @Local(name = "state") BlockBreakingRenderState state, @Local(name = "model") BlockStateModel model, @Share("mutableMesh") LocalRef<MutableMesh> mutableMeshRef) {
MutableMesh mutableMesh = mutableMeshRef.get();
mutableMesh.clear();
model.emitQuads(mutableMesh.emitter(), BlockAndTintGetter.EMPTY, state.blockPos(), state.blockState(), random, _ -> false);
submitNodeCollector.submitBreakingBlockModel(poseStack, parts, mutableMesh.immutableCopy(), progress);
}
}

View file

@ -16,55 +16,72 @@
package net.fabricmc.fabric.mixin.client.renderer.block.render;
import java.util.List;
import com.llamalad7.mixinextras.sugar.Local;
import com.llamalad7.mixinextras.sugar.Share;
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.SubmitNodeCollection;
import net.minecraft.client.renderer.block.BlockAndTintGetter;
import net.minecraft.client.renderer.block.BlockQuadOutput;
import net.minecraft.client.renderer.block.ModelBlockRenderer;
import net.minecraft.client.renderer.block.MovingBlockRenderState;
import net.minecraft.client.renderer.block.dispatch.BlockStateModel;
import net.minecraft.client.renderer.feature.FeatureFrameContext;
import net.minecraft.client.renderer.feature.MovingBlockFeatureRenderer;
import net.minecraft.client.resources.model.geometry.BakedQuad;
import net.minecraft.client.renderer.feature.RenderTypeFeatureRenderer;
import net.minecraft.client.renderer.rendertype.RenderType;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.BlockPos;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.state.BlockState;
import net.fabricmc.fabric.api.client.renderer.v1.Renderer;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.MutableQuadView;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.client.renderer.v1.render.AltModelBlockRenderer;
import net.fabricmc.fabric.api.client.renderer.v1.render.ChunkSectionLayerHelper;
import net.fabricmc.fabric.impl.client.renderer.MovingBlockQuadConsumer;
@Mixin(MovingBlockFeatureRenderer.class)
abstract class MovingBlockFeatureRendererMixin {
@Inject(method = "render", at = @At(value = "INVOKE", target = "net/minecraft/client/renderer/block/ModelBlockRenderer.<init>(ZZLnet/minecraft/client/color/block/BlockColors;)V"))
private void beforeInitBlockRenderer(SubmitNodeCollection nodeCollection, FeatureFrameContext context, boolean translucent, CallbackInfo ci, @Local(name = "poseStack") PoseStack poseStack, @Share("altBlockRenderer") LocalRef<AltModelBlockRenderer> altBlockRenderer, @Share("altQuadOutput") LocalRef<QuadEmitter> altQuadOutput) {
altBlockRenderer.set(Renderer.get().altModelBlockRenderer(context.options().ambientOcclusion, false, Minecraft.getInstance().getBlockColors()));
altQuadOutput.set(Renderer.get().quadEmitter(quad -> {
quad.buffer(0, poseStack.last(), context.bufferSource().getBuffer(ChunkSectionLayerHelper.getMovingBlockRenderType(quad.chunkLayer())));
}));
abstract class MovingBlockFeatureRendererMixin extends RenderTypeFeatureRenderer<MovingBlockFeatureRenderer.Submit> {
@Shadow
@Final
private PoseStack poseStack;
@Inject(method = "buildGroup", at = @At(value = "INVOKE", target = "net/minecraft/client/renderer/block/ModelBlockRenderer.<init>(ZZLnet/minecraft/client/color/block/BlockColors;)V"))
private void beforeInitBlockRenderer(FeatureFrameContext context, List<MovingBlockFeatureRenderer.Submit> submits, CallbackInfo ci, @Share("altBlockRenderer") LocalRef<AltModelBlockRenderer> altBlockRenderer, @Share("altQuadOutput") LocalRef<QuadEmitter> altQuadOutput, @Share("quadConsumer") LocalRef<MovingBlockQuadConsumer> quadConsumerRef) {
altBlockRenderer.set(Renderer.get().altModelBlockRenderer(context.options().ambientOcclusion, false, context.blockColors()));
MovingBlockQuadConsumer quadConsumer = new MovingBlockQuadConsumer() {
@Override
public void accept(MutableQuadView quad) {
RenderType renderType = ChunkSectionLayerHelper.getMovingBlockRenderType(quad.chunkLayer());
VertexConsumer buffer;
if (outlineColor != 0 && renderType.outline().isPresent()) {
quad.color(outlineColor, outlineColor, outlineColor, outlineColor);
buffer = getVertexBuilder(renderType.outline().get());
} else {
buffer = getVertexBuilder(renderType);
}
quad.buffer(OverlayTexture.NO_OVERLAY, poseStack.last(), buffer);
}
};
altQuadOutput.set(Renderer.get().quadEmitter(quadConsumer));
quadConsumerRef.set(quadConsumer);
}
@Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/block/dispatch/BlockStateModel;hasMaterialFlag(I)Z"))
private boolean hasMaterialFlagProxy(BlockStateModel model, @BakedQuad.MaterialFlags int flag, @Local(name = "movingBlockRenderState") MovingBlockRenderState movingBlockRenderState, @Local(name = "blockState") BlockState blockState) {
RandomSource random = RandomSource.createThreadLocalInstance(0L);
long blockSeed = blockState.getSeed(movingBlockRenderState.randomSeedPos);
random.setSeed(blockSeed);
return model.hasMaterialFlag(movingBlockRenderState, movingBlockRenderState.blockPos, blockState, random, flag);
}
@Redirect(method = "render", at = @At(value = "INVOKE", target = "net/minecraft/client/renderer/block/ModelBlockRenderer.tesselateBlock(Lnet/minecraft/client/renderer/block/BlockQuadOutput;FFFLnet/minecraft/client/renderer/block/BlockAndTintGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/client/renderer/block/dispatch/BlockStateModel;J)V"))
private void tesselateBlockProxy(ModelBlockRenderer blockRenderer, BlockQuadOutput output, float x, float y, float z, BlockAndTintGetter level, BlockPos pos, BlockState blockState, BlockStateModel model, long seed, @Share("altBlockRenderer") LocalRef<AltModelBlockRenderer> altBlockRenderer, @Share("altQuadOutput") LocalRef<QuadEmitter> altQuadOutput) {
@Redirect(method = "buildGroup", at = @At(value = "INVOKE", target = "net/minecraft/client/renderer/block/ModelBlockRenderer.tesselateBlock(Lnet/minecraft/client/renderer/block/BlockQuadOutput;FFFLnet/minecraft/client/renderer/block/BlockAndTintGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/client/renderer/block/dispatch/BlockStateModel;J)V"))
private void tesselateBlockProxy(ModelBlockRenderer blockRenderer, BlockQuadOutput output, float x, float y, float z, BlockAndTintGetter level, BlockPos pos, BlockState blockState, BlockStateModel model, long seed, @Local(name = "submit") MovingBlockFeatureRenderer.Submit submit, @Share("altBlockRenderer") LocalRef<AltModelBlockRenderer> altBlockRenderer, @Share("altQuadOutput") LocalRef<QuadEmitter> altQuadOutput, @Share("quadConsumer") LocalRef<MovingBlockQuadConsumer> quadConsumer) {
quadConsumer.get().outlineColor(submit.outlineColor());
altBlockRenderer.get().tesselateBlock(altQuadOutput.get(), x, y, z, level, pos, blockState, model, seed);
}
}

View file

@ -23,5 +23,5 @@ import net.minecraft.client.resources.model.sprite.MaterialBaker;
import net.fabricmc.fabric.api.client.renderer.v1.sprite.FabricMaterialBaker;
@Mixin(MaterialBaker.class)
interface MaterialBakerMixin extends FabricMaterialBaker {
abstract class MaterialBakerMixin implements FabricMaterialBaker {
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.client.renderer.sprite;
import org.jspecify.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import net.minecraft.client.renderer.texture.SpriteLoader;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.data.AtlasIds;
import net.minecraft.resources.Identifier;
import net.fabricmc.fabric.api.client.renderer.v1.sprite.FabricMaterialBaker;
import net.fabricmc.fabric.api.client.renderer.v1.sprite.SpriteFinder;
import net.fabricmc.fabric.impl.client.renderer.MissingSpriteFinderImpl;
@Mixin(ModelManager.BlockOnlyMaterialBaker.class)
abstract class ModelManagerBlockOnlyMaterialBakerMixin implements FabricMaterialBaker {
@Shadow
@Final
private SpriteLoader.Preparations blockAtlas;
@Unique
@Nullable
private volatile MissingSpriteFinderImpl missingSpriteFinder;
@Override
public SpriteFinder spriteFinder(Identifier atlasId) {
if (atlasId.equals(AtlasIds.BLOCKS)) {
return blockAtlas.spriteFinder();
}
MissingSpriteFinderImpl result = missingSpriteFinder;
if (result == null) {
synchronized (this) {
result = missingSpriteFinder;
if (result == null) {
missingSpriteFinder = result = new MissingSpriteFinderImpl(blockAtlas.missing());
}
}
}
return result;
}
}

View file

@ -24,7 +24,6 @@ import org.spongepowered.asm.mixin.Unique;
import net.minecraft.client.renderer.texture.SpriteLoader;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.client.resources.model.sprite.Material;
import net.minecraft.data.AtlasIds;
import net.minecraft.resources.Identifier;
@ -32,11 +31,8 @@ import net.fabricmc.fabric.api.client.renderer.v1.sprite.FabricMaterialBaker;
import net.fabricmc.fabric.api.client.renderer.v1.sprite.SpriteFinder;
import net.fabricmc.fabric.impl.client.renderer.MissingSpriteFinderImpl;
@Mixin(ModelManager.MaterialBakerImpl.class)
abstract class ModelManagerMaterialBakerImplMixin implements FabricMaterialBaker {
@Shadow
@Final
private Material.Baked blockMissing;
@Mixin(ModelManager.CombinedBlockItemMaterialBaker.class)
abstract class ModelManagerCombinedBlockItemMaterialBakerMixin implements FabricMaterialBaker {
@Shadow
@Final
private SpriteLoader.Preparations blockAtlas;
@ -63,7 +59,7 @@ abstract class ModelManagerMaterialBakerImplMixin implements FabricMaterialBaker
result = missingSpriteFinder;
if (result == null) {
missingSpriteFinder = result = new MissingSpriteFinderImpl(blockMissing.sprite());
missingSpriteFinder = result = new MissingSpriteFinderImpl(blockAtlas.missing());
}
}
}

View file

@ -16,67 +16,112 @@
package net.fabricmc.fabric.mixin.client.renderer.submit;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import com.llamalad7.mixinextras.sugar.Local;
import com.mojang.blaze3d.vertex.PoseStack;
import org.jspecify.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.Redirect;
import net.minecraft.client.renderer.OrderedSubmitNodeCollector;
import net.minecraft.client.renderer.SubmitNodeCollection;
import net.minecraft.client.renderer.block.BlockModelRenderState;
import net.minecraft.client.renderer.block.MovingBlockRenderState;
import net.minecraft.client.renderer.block.dispatch.BlockStateModel;
import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart;
import net.minecraft.client.renderer.chunk.ChunkSectionLayer;
import net.minecraft.client.renderer.feature.phase.SimpleFeatureRenderPhase;
import net.minecraft.client.renderer.feature.phase.TranslucentFeatureRenderPhase;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.renderer.rendertype.RenderType;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.geometry.BakedQuad;
import net.minecraft.util.LightCoordsUtil;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.level.block.state.BlockState;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.Mesh;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.MeshView;
import net.fabricmc.fabric.api.client.renderer.v1.render.FabricSubmitNodeCollection;
import net.fabricmc.fabric.api.client.renderer.v1.render.submit.ExtendedBlockModelSubmit;
import net.fabricmc.fabric.api.client.renderer.v1.render.submit.ExtendedItemSubmit;
@Mixin(SubmitNodeCollection.class)
abstract class SubmitNodeCollectionMixin implements OrderedSubmitNodeCollector, FabricSubmitNodeCollection {
abstract class SubmitNodeCollectionMixin implements OrderedSubmitNodeCollector {
@Shadow
private boolean wasUsed;
@Final
public SimpleFeatureRenderPhase solid;
@Shadow
@Final
public TranslucentFeatureRenderPhase translucentBlocksAndItems;
@Shadow
@Final
public SimpleFeatureRenderPhase breakingOverlay;
@Shadow
@Final
public SimpleFeatureRenderPhase outline;
@Unique
private final List<ExtendedBlockModelSubmit> extendedBlockModelSubmits = new ArrayList<>();
@Unique
private final List<ExtendedItemSubmit> extendedItemSubmits = new ArrayList<>();
@Shadow
@Nullable
private static RenderType getOutlineRenderType(RenderType renderType) {
return null;
}
@Override
public void submitBlockModel(PoseStack poseStack, Function<ChunkSectionLayer, RenderType> renderTypeFunction, boolean translucent, List<BlockStateModelPart> parts, @Nullable Mesh mesh, int[] tintLayers, int lightCoords, int overlayCoords, int outlineColor) {
wasUsed = true;
extendedBlockModelSubmits.add(new ExtendedBlockModelSubmit(poseStack.last().copy(), renderTypeFunction, translucent, parts, mesh, tintLayers, lightCoords, overlayCoords, outlineColor));
PoseStack.Pose pose = poseStack.last().copy();
Function<ChunkSectionLayer, @Nullable RenderType> filteringRenderTypeFunction = layer -> {
RenderType renderType = renderTypeFunction.apply(layer);
return renderType.isOutline() ? null : renderType;
};
ExtendedBlockModelSubmit submit = new ExtendedBlockModelSubmit(pose, filteringRenderTypeFunction, parts, mesh, tintLayers, lightCoords, overlayCoords, -1, null);
if (translucent) {
translucentBlocksAndItems.submit(submit);
} else {
solid.submit(submit);
}
if (outlineColor != 0) {
Function<ChunkSectionLayer, @Nullable RenderType> outlineRenderTypeFunction = layer -> getOutlineRenderType(renderTypeFunction.apply(layer));
outline.submit(new ExtendedBlockModelSubmit(pose, outlineRenderTypeFunction, parts, mesh, BlockModelRenderState.EMPTY_TINTS, LightCoordsUtil.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, outlineColor, null));
}
}
@Override
public void submitBreakingBlockModel(PoseStack poseStack, List<BlockStateModelPart> parts, Mesh mesh, int progress) {
PoseStack.Pose pose = poseStack.last().copy();
RenderType renderType = ModelBakery.DESTROY_TYPES.get(progress);
breakingOverlay.submit(new ExtendedBlockModelSubmit(pose, _ -> renderType, List.copyOf(parts), mesh, BlockModelRenderState.EMPTY_TINTS, LightCoordsUtil.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, 0, pose));
}
@Override
public void submitItem(PoseStack poseStack, ItemDisplayContext displayContext, int lightCoords, int overlayCoords, int outlineColor, int[] tintLayers, List<BakedQuad> quads, MeshView mesh, ItemStackRenderState.FoilType foilType) {
this.wasUsed = true;
extendedItemSubmits.add(new ExtendedItemSubmit(poseStack.last().copy(), displayContext, lightCoords, overlayCoords, outlineColor, tintLayers, quads, mesh, foilType));
PoseStack.Pose pose = poseStack.last().copy();
ExtendedItemSubmit submit = new ExtendedItemSubmit(pose, displayContext, lightCoords, overlayCoords, 0, tintLayers, quads, mesh, foilType);
if (submit.hasTranslucency()) {
translucentBlocksAndItems.submit(submit);
} else {
solid.submit(submit);
}
if (outlineColor != 0) {
outline.submit(new ExtendedItemSubmit(pose, displayContext, LightCoordsUtil.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, outlineColor, ItemStackRenderState.LayerRenderState.EMPTY_TINTS, quads, mesh, ItemStackRenderState.FoilType.NONE));
}
}
@Override
public List<ExtendedBlockModelSubmit> getExtendedBlockModelSubmits() {
return extendedBlockModelSubmits;
}
@Override
public List<ExtendedItemSubmit> getExtendedItemSubmits() {
return extendedItemSubmits;
}
@Inject(method = "clear", at = @At("RETURN"))
private void onReturnClear(CallbackInfo ci) {
extendedBlockModelSubmits.clear();
extendedItemSubmits.clear();
@Redirect(method = "submitMovingBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/block/dispatch/BlockStateModel;hasMaterialFlag(I)Z"))
private boolean hasMaterialFlagProxy(BlockStateModel model, @BakedQuad.MaterialFlags int flag, @Local(name = "movingBlockRenderState") MovingBlockRenderState movingBlockRenderState) {
BlockState blockState = movingBlockRenderState.blockState;
long randomSeed = blockState.getSeed(movingBlockRenderState.randomSeedPos);
RandomSource random = RandomSource.createThreadLocalInstance(randomSeed);
return model.hasMaterialFlag(movingBlockRenderState, movingBlockRenderState.blockPos, blockState, random, flag);
}
}

View file

@ -42,6 +42,11 @@ abstract class SubmitNodeStorageMixin implements SubmitNodeCollector {
order(0).submitBlockModel(poseStack, renderTypeFunction, translucent, parts, mesh, tintLayers, lightCoords, overlayCoords, outlineColor);
}
@Override
public void submitBreakingBlockModel(PoseStack poseStack, List<BlockStateModelPart> parts, Mesh mesh, int progress) {
order(0).submitBreakingBlockModel(poseStack, parts, mesh, progress);
}
@Override
public void submitItem(PoseStack poseStack, ItemDisplayContext displayContext, int lightCoords, int overlayCoords, int outlineColor, int[] tintLayers, List<BakedQuad> quads, MeshView mesh, ItemStackRenderState.FoilType foilType) {
order(0).submitItem(poseStack, displayContext, lightCoords, overlayCoords, outlineColor, tintLayers, quads, mesh, foilType);

View file

@ -1,14 +1,14 @@
classTweaker v1 official
accessible class net/minecraft/client/renderer/block/dispatch/multipart/MultiPartModel$SharedBakedState
accessible method net/minecraft/client/resources/model/geometry/QuadCollection <init> (Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;)V
accessible class net/minecraft/client/resources/model/ModelManager$MaterialBakerImpl
accessible class net/minecraft/client/resources/model/ModelManager$BlockOnlyMaterialBaker
accessible class net/minecraft/client/resources/model/ModelManager$CombinedBlockItemMaterialBaker
transitive-inject-interface net/minecraft/client/renderer/block/dispatch/BlockStateModel net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockStateModel
transitive-inject-interface net/minecraft/client/renderer/block/dispatch/BlockStateModelPart net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockStateModelPart
transitive-inject-interface net/minecraft/client/renderer/block/BlockStateModelSet net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockStateModelSet
transitive-inject-interface net/minecraft/client/renderer/block/BlockModelRenderState net/fabricmc/fabric/api/client/renderer/v1/render/FabricBlockModelRenderState
transitive-inject-interface net/minecraft/client/renderer/item/ItemStackRenderState$LayerRenderState net/fabricmc/fabric/api/client/renderer/v1/render/FabricLayerRenderState
transitive-inject-interface net/minecraft/client/renderer/OrderedSubmitNodeCollector net/fabricmc/fabric/api/client/renderer/v1/render/FabricOrderedSubmitNodeCollector
transitive-inject-interface net/minecraft/client/renderer/SubmitNodeCollection net/fabricmc/fabric/api/client/renderer/v1/render/FabricSubmitNodeCollection
transitive-inject-interface net/minecraft/client/resources/model/sprite/MaterialBaker net/fabricmc/fabric/api/client/renderer/v1/sprite/FabricMaterialBaker
transitive-inject-interface net/minecraft/client/renderer/texture/SpriteLoader$Preparations net/fabricmc/fabric/api/client/renderer/v1/sprite/FabricPreparations
transitive-inject-interface net/minecraft/client/renderer/texture/TextureAtlas net/fabricmc/fabric/api/client/renderer/v1/sprite/FabricTextureAtlas

View file

@ -14,17 +14,18 @@
"block.particle.BlockStateModelSetMixin",
"block.particle.ScreenEffectRendererMixin",
"block.particle.TerrainParticleMixin",
"block.render.BlockModelFeatureRendererMixin",
"block.render.BlockModelRenderStateMixin",
"block.render.BlockStateModelWrapperMixin",
"block.render.LevelExtractorMixin",
"block.render.LevelRendererMixin",
"block.render.MovingBlockFeatureRendererMixin",
"block.render.SectionCompilerMixin",
"item.CuboidItemModelWrapperMixin",
"item.ItemStackRenderStateLayerRenderStateMixin",
"item.ItemStackRenderStateMixin",
"sprite.MaterialBakerMixin",
"sprite.ModelManagerMaterialBakerImplMixin",
"sprite.ModelManagerBlockOnlyMaterialBakerMixin",
"sprite.ModelManagerCombinedBlockItemMaterialBakerMixin",
"sprite.SpriteLoaderPreparationsMixin",
"sprite.TextureAtlasMixin",
"submit.OrderedSubmitNodeCollectorMixin",

View file

@ -28,8 +28,6 @@ import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.minecraft.client.renderer.MultiBufferSource;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.renderer.v1.Renderer;
import net.fabricmc.fabric.api.util.TriState;
@ -51,9 +49,6 @@ public class Indigo implements ClientModInitializer {
/** If set the default config file will be generated on startup, restoring pre 26.1 behavior. */
private static final boolean GENERATE_CONFIG_FILE = System.getProperty("fabric.indigo.generateConfigFile") != null;
// A hack for Mixins, check usages
public static final ScopedValue<MultiBufferSource> LEVEL_RENDERER_BUFFER_SOURCE = ScopedValue.newInstance();
private static boolean asBoolean(@Nullable String property, boolean defValue) {
return asTriState(property).orElse(defValue);
}

View file

@ -1,152 +0,0 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.impl.client.indigo.renderer.render;
import java.util.List;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import org.jspecify.annotations.Nullable;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.OutlineBufferSource;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.renderer.rendertype.RenderType;
import net.minecraft.client.resources.model.geometry.BakedQuad;
import net.minecraft.util.LightCoordsUtil;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.MeshView;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.client.renderer.v1.render.FabricLayerRenderState;
import net.fabricmc.fabric.api.client.renderer.v1.render.FabricSubmitNodeCollection;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.EncodingFormat;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl;
import net.fabricmc.fabric.mixin.client.indigo.renderer.ItemFeatureRendererAccessor;
/**
* Used during item buffering to support geometry added through {@link FabricLayerRenderState#emitter()}.
*/
public class AltItemRenderer {
private final MutableQuadViewImpl emitter = new MutableQuadViewImpl() {
{
data = new int[EncodingFormat.TOTAL_STRIDE];
clear();
}
@Override
protected void emitDirectly() {
bufferQuad(this);
}
};
private MultiBufferSource bufferSource;
private OutlineBufferSource outlineBufferSource;
private boolean translucent;
private FabricSubmitNodeCollection.ExtendedItemSubmit submit;
private PoseStack.@Nullable Pose foilDecalPose;
public void prepare(MultiBufferSource.BufferSource bufferSource, OutlineBufferSource outlineBufferSource, boolean translucent) {
this.bufferSource = bufferSource;
this.outlineBufferSource = outlineBufferSource;
this.translucent = translucent;
}
public void clear() {
bufferSource = null;
outlineBufferSource = null;
}
public void renderItem(FabricSubmitNodeCollection.ExtendedItemSubmit submit) {
this.submit = submit;
if (submit.outlineColor() != 0) {
outlineBufferSource.setColor(submit.outlineColor());
}
bufferQuads(submit.quads(), submit.mesh());
foilDecalPose = null;
}
private void bufferQuads(List<BakedQuad> vanillaQuads, MeshView mesh) {
QuadEmitter emitter = this.emitter;
emitter.clear();
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < vanillaQuads.size(); i++) {
final BakedQuad q = vanillaQuads.get(i);
emitter.fromBakedQuad(q);
emitter.emit();
}
mesh.outputTo(emitter);
}
private void bufferQuad(MutableQuadViewImpl quad) {
final RenderType renderType = quad.itemRenderType();
if (renderType.hasBlending() != translucent) {
return;
}
shadeQuad(quad, quad.emissive());
tintQuad(quad);
final FabricSubmitNodeCollection.ExtendedItemSubmit submit = this.submit;
final ItemStackRenderState.FoilType foilType = quad.foilType() == null ? submit.foilType() : quad.foilType();
if (foilType != ItemStackRenderState.FoilType.NONE) {
final PoseStack.Pose foilDecalPose;
if (foilType == ItemStackRenderState.FoilType.SPECIAL) {
if (this.foilDecalPose == null) {
this.foilDecalPose = ItemFeatureRendererAccessor.fabric_computeFoilDecalPose(submit.displayContext(), submit.pose());
}
foilDecalPose = this.foilDecalPose;
} else {
foilDecalPose = null;
}
final VertexConsumer foilBuffer = ItemFeatureRendererAccessor.fabric_getFoilBuffer(bufferSource, renderType, foilDecalPose);
quad.buffer(submit.overlayCoords(), submit.pose(), foilBuffer);
}
if (submit.outlineColor() != 0) {
quad.buffer(submit.overlayCoords(), submit.pose(), outlineBufferSource.getBuffer(renderType));
}
quad.buffer(submit.overlayCoords(), submit.pose(), bufferSource.getBuffer(renderType));
}
private void shadeQuad(MutableQuadViewImpl quad, boolean emissive) {
if (emissive) {
quad.lightmap(LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT);
} else {
quad.minLightmap(submit.lightCoords());
}
}
private void tintQuad(MutableQuadViewImpl quad) {
final int tintIndex = quad.tintIndex();
if (tintIndex >= 0 && tintIndex < submit.tintLayers().length) {
quad.multiplyColor(submit.tintLayers()[tintIndex]);
}
}
}

View file

@ -0,0 +1,178 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.impl.client.indigo.renderer.render;
import java.util.List;
import java.util.function.Function;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.QuadInstance;
import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator;
import com.mojang.blaze3d.vertex.VertexConsumer;
import org.jspecify.annotations.Nullable;
import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart;
import net.minecraft.client.renderer.chunk.ChunkSectionLayer;
import net.minecraft.client.renderer.feature.FeatureFrameContext;
import net.minecraft.client.renderer.feature.RenderTypeFeatureRenderer;
import net.minecraft.client.renderer.rendertype.RenderType;
import net.minecraft.client.resources.model.geometry.BakedQuad;
import net.minecraft.core.Direction;
import net.minecraft.util.ARGB;
import net.minecraft.util.LightCoordsUtil;
import net.fabricmc.fabric.api.client.renderer.v1.render.submit.ExtendedBlockModelSubmit;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.EncodingFormat;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl;
public class ExtendedBlockModelFeatureRenderer extends RenderTypeFeatureRenderer<ExtendedBlockModelSubmit> {
private static final Direction[] DIRECTIONS = Direction.values();
private final QuadInstance quadInstance = new QuadInstance();
private final BufferCache bufferCache = new BufferCache();
private final MutableQuadViewImpl emitter = new MutableQuadViewImpl() {
{
data = new int[EncodingFormat.TOTAL_STRIDE];
clear();
}
@Override
protected void emitDirectly() {
bufferQuad(this);
}
};
private ExtendedBlockModelSubmit submit;
@Override
protected void buildGroup(FeatureFrameContext context, List<ExtendedBlockModelSubmit> submits) {
BufferCache bufferCache = this.bufferCache;
MutableQuadViewImpl emitter = this.emitter;
for (ExtendedBlockModelSubmit submit : submits) {
bufferCache.prepare(submit.renderTypeFunction(), submit.sheetedDecalPose());
quadInstance.setLightCoords(submit.lightCoords());
quadInstance.setOverlayCoords(submit.overlayCoords());
for (BlockStateModelPart part : submit.modelParts()) {
putPartQuads(part, submit.pose(), quadInstance, submit.tintColor(), submit.tintLayers(), bufferCache);
}
if (submit.mesh() != null) {
this.submit = submit;
submit.mesh().outputTo(emitter);
}
}
bufferCache.clear();
submit = null;
}
private void putPartQuads(BlockStateModelPart part, PoseStack.Pose pose, QuadInstance quadInstance, int baseTintColor, int[] tintLayers, BufferCache bufferCache) {
for (Direction direction : DIRECTIONS) {
for (BakedQuad quad : part.getQuads(direction)) {
VertexConsumer buffer = bufferCache.getBuffer(quad.materialInfo().layer());
if (buffer == null) {
continue;
}
putQuad(pose, quad, quadInstance, baseTintColor, tintLayers, buffer);
}
}
for (BakedQuad quad : part.getQuads(null)) {
VertexConsumer buffer = bufferCache.getBuffer(quad.materialInfo().layer());
if (buffer == null) {
continue;
}
putQuad(pose, quad, quadInstance, baseTintColor, tintLayers, buffer);
}
}
private static void putQuad(PoseStack.Pose pose, BakedQuad quad, QuadInstance instance, int baseTintColor, int[] tintLayers, VertexConsumer buffer) {
int tintIndex = quad.materialInfo().tintIndex();
boolean useTintLayer = tintIndex != -1 && tintIndex < tintLayers.length;
instance.setColor(useTintLayer ? ARGB.multiply(baseTintColor, tintLayers[tintIndex]) : baseTintColor);
buffer.putBakedQuad(pose, quad, instance);
}
private void bufferQuad(MutableQuadViewImpl quad) {
VertexConsumer buffer = bufferCache.getBuffer(quad.chunkLayer());
if (buffer == null) {
return;
}
if (quad.emissive()) {
quad.lightmap(LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT);
} else {
quad.minLightmap(submit.lightCoords());
}
int[] tintLayers = submit.tintLayers();
int baseTintColor = submit.tintColor();
int tintIndex = quad.tintIndex();
boolean useTintLayer = tintIndex != -1 && tintIndex < tintLayers.length;
quad.multiplyColor(useTintLayer ? ARGB.multiply(baseTintColor, tintLayers[tintIndex]) : baseTintColor);
quad.buffer(submit.overlayCoords(), submit.pose(), buffer);
}
private class BufferCache {
private Function<ChunkSectionLayer, @Nullable RenderType> renderTypeFunction;
private PoseStack.@Nullable Pose sheetedDecalPose;
@Nullable
private ChunkSectionLayer lastLayer;
@Nullable
private VertexConsumer lastBuffer;
public void prepare(Function<ChunkSectionLayer, @Nullable RenderType> renderTypeFunction, PoseStack.@Nullable Pose sheetedDecalPose) {
this.renderTypeFunction = renderTypeFunction;
this.sheetedDecalPose = sheetedDecalPose;
lastLayer = null;
}
public void clear() {
renderTypeFunction = null;
sheetedDecalPose = null;
lastLayer = null;
lastBuffer = null;
}
@Nullable
public VertexConsumer getBuffer(ChunkSectionLayer layer) {
if (layer != lastLayer) {
lastLayer = layer;
RenderType renderType = renderTypeFunction.apply(layer);
if (renderType == null) {
lastBuffer = null;
} else {
VertexConsumer buffer = getVertexBuilder(renderType);
lastBuffer = sheetedDecalPose != null ? new SheetedDecalTextureGenerator(buffer, sheetedDecalPose, 1.0F) : buffer;
}
}
return lastBuffer;
}
}
}

View file

@ -0,0 +1,168 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.impl.client.indigo.renderer.render;
import java.util.List;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator;
import com.mojang.blaze3d.vertex.VertexConsumer;
import org.jspecify.annotations.Nullable;
import net.minecraft.client.renderer.feature.FeatureFrameContext;
import net.minecraft.client.renderer.feature.RenderTypeFeatureRenderer;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.client.renderer.rendertype.RenderType;
import net.minecraft.client.renderer.rendertype.RenderTypes;
import net.minecraft.client.resources.model.geometry.BakedQuad;
import net.minecraft.util.LightCoordsUtil;
import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.client.renderer.v1.render.submit.ExtendedItemSubmit;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.EncodingFormat;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl;
import net.fabricmc.fabric.mixin.client.indigo.renderer.ItemFeatureRendererAccessor;
public class ExtendedItemFeatureRenderer extends RenderTypeFeatureRenderer<ExtendedItemSubmit> {
private final MutableQuadViewImpl emitter = new MutableQuadViewImpl() {
{
data = new int[EncodingFormat.TOTAL_STRIDE];
clear();
}
@Override
protected void emitDirectly() {
switch (outputType) {
case MAIN -> bufferMain(this);
case OUTLINE -> bufferOutline(this);
case FOIL -> bufferFoil(this);
}
}
};
private ExtendedItemSubmit submit;
private PoseStack.@Nullable Pose foilDecalPose;
private OutputType outputType;
@Override
protected void buildGroup(FeatureFrameContext context, List<ExtendedItemSubmit> submits) {
for (ExtendedItemSubmit submit : submits) {
prepareSubmit(submit, false);
}
for (ExtendedItemSubmit submit : submits) {
prepareSubmit(submit, true);
}
submit = null;
foilDecalPose = null;
}
private void prepareSubmit(ExtendedItemSubmit submit, boolean foil) {
this.submit = submit;
if (foil) {
foilDecalPose = null;
outputType = OutputType.FOIL;
} else if (submit.outlineColor() != 0) {
outputType = OutputType.OUTLINE;
} else {
outputType = OutputType.MAIN;
}
QuadEmitter emitter = this.emitter;
emitter.clear();
List<BakedQuad> vanillaQuads = submit.quads();
//noinspection ForLoopReplaceableByForEach
for (int i = 0; i < vanillaQuads.size(); i++) {
final BakedQuad q = vanillaQuads.get(i);
emitter.fromBakedQuad(q);
emitter.emit();
}
submit.mesh().outputTo(emitter);
}
private void bufferMain(MutableQuadViewImpl quad) {
if (quad.emissive()) {
quad.lightmap(LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT);
} else {
quad.minLightmap(submit.lightCoords());
}
int tintIndex = quad.tintIndex();
if (tintIndex >= 0 && tintIndex < submit.tintLayers().length) {
quad.multiplyColor(submit.tintLayers()[tintIndex]);
}
quad.buffer(submit.overlayCoords(), submit.pose(), getVertexBuilder(quad.itemRenderType()));
}
private void bufferOutline(MutableQuadViewImpl quad) {
RenderType renderType = quad.itemRenderType().outline().orElse(null);
if (renderType != null) {
int outlineColor = submit.outlineColor();
quad.color(outlineColor, outlineColor, outlineColor, outlineColor);
quad.buffer(submit.overlayCoords(), submit.pose(), getVertexBuilder(renderType));
}
}
private void bufferFoil(MutableQuadViewImpl quad) {
ItemStackRenderState.FoilType quadFoilType = quad.foilType();
ItemStackRenderState.FoilType foilType = quadFoilType == null ? submit.foilType() : quadFoilType;
if (foilType == ItemStackRenderState.FoilType.NONE) {
return;
}
PoseStack.Pose foilDecalPose;
if (foilType == ItemStackRenderState.FoilType.SPECIAL) {
if (this.foilDecalPose == null) {
this.foilDecalPose = ItemFeatureRendererAccessor.fabric_computeFoilDecalPose(submit.displayContext(), submit.pose());
}
foilDecalPose = this.foilDecalPose;
} else {
foilDecalPose = null;
}
VertexConsumer foilBuffer = getFoilBuffer(quad.itemRenderType(), foilDecalPose);
quad.buffer(submit.overlayCoords(), submit.pose(), foilBuffer);
}
private VertexConsumer getFoilBuffer(RenderType renderType, PoseStack.@Nullable Pose foilDecalPose) {
RenderType foilRenderType = ItemFeatureRendererAccessor.fabric_useTransparentGlint(renderType) ? RenderTypes.glintTranslucent() : RenderTypes.glint();
VertexConsumer foilBuffer = getVertexBuilder(foilRenderType);
if (foilDecalPose != null) {
foilBuffer = new SheetedDecalTextureGenerator(foilBuffer, foilDecalPose, 0.0078125F);
}
return foilBuffer;
}
private enum OutputType {
MAIN,
OUTLINE,
FOIL
}
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.client.indigo.renderer;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.client.renderer.feature.FeatureRenderDispatcher;
import net.minecraft.client.renderer.feature.FeatureRendererMap;
import net.fabricmc.fabric.api.client.renderer.v1.render.submit.ExtendedBlockModelSubmit;
import net.fabricmc.fabric.api.client.renderer.v1.render.submit.ExtendedItemSubmit;
import net.fabricmc.fabric.impl.client.indigo.renderer.render.ExtendedBlockModelFeatureRenderer;
import net.fabricmc.fabric.impl.client.indigo.renderer.render.ExtendedItemFeatureRenderer;
@Mixin(FeatureRenderDispatcher.class)
abstract class FeatureRenderDispatcherMixin {
@Shadow
@Final
private FeatureRendererMap featureRenderers;
@Inject(method = "<init>", at = @At("RETURN"))
private void registerExtendedFeatureRenderers(CallbackInfo ci) {
featureRenderers.put(
ExtendedBlockModelSubmit.TYPE,
new ExtendedBlockModelFeatureRenderer()
);
featureRenderers.put(
ExtendedItemSubmit.TYPE,
new ExtendedItemFeatureRenderer()
);
}
}

View file

@ -17,25 +17,22 @@
package net.fabricmc.fabric.mixin.client.indigo.renderer;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import org.jspecify.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.feature.ItemFeatureRenderer;
import net.minecraft.client.renderer.rendertype.RenderType;
import net.minecraft.world.item.ItemDisplayContext;
@Mixin(ItemFeatureRenderer.class)
public interface ItemFeatureRendererAccessor {
@Invoker("getFoilBuffer")
static VertexConsumer fabric_getFoilBuffer(MultiBufferSource bufferSource, RenderType renderType, PoseStack.@Nullable Pose foilDecalPose) {
throw new AssertionError();
}
@Invoker("computeFoilDecalPose")
static PoseStack.Pose fabric_computeFoilDecalPose(ItemDisplayContext type, PoseStack.Pose pose) {
throw new AssertionError();
}
@Invoker("useTransparentGlint")
static boolean fabric_useTransparentGlint(RenderType renderType) {
throw new AssertionError();
}
}

View file

@ -1,59 +0,0 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.client.indigo.renderer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.SubmitNodeCollection;
import net.minecraft.client.renderer.feature.FeatureFrameContext;
import net.minecraft.client.renderer.feature.ItemFeatureRenderer;
import net.fabricmc.fabric.api.client.renderer.v1.render.FabricSubmitNodeCollection;
import net.fabricmc.fabric.impl.client.indigo.renderer.render.AltItemRenderer;
@Mixin(ItemFeatureRenderer.class)
abstract class ItemFeatureRendererMixin {
@Unique
private final AltItemRenderer altItemRenderer = new AltItemRenderer();
@Inject(method = "renderSolid", at = @At("RETURN"))
private void onReturnRenderSolid(SubmitNodeCollection nodeCollection, FeatureFrameContext context, CallbackInfo ci) {
altItemRenderer.prepare((MultiBufferSource.BufferSource) context.bufferSource(), context.outlineBufferSource(), false);
for (FabricSubmitNodeCollection.ExtendedItemSubmit submit : nodeCollection.getExtendedItemSubmits()) {
altItemRenderer.renderItem(submit);
}
altItemRenderer.clear();
}
@Inject(method = "renderTranslucent", at = @At("RETURN"))
private void onReturnRenderTranslucent(SubmitNodeCollection nodeCollection, FeatureFrameContext context, CallbackInfo ci) {
altItemRenderer.prepare((MultiBufferSource.BufferSource) context.bufferSource(), context.outlineBufferSource(), true);
for (FabricSubmitNodeCollection.ExtendedItemSubmit submit : nodeCollection.getExtendedItemSubmits()) {
altItemRenderer.renderItem(submit);
}
altItemRenderer.clear();
}
}

View file

@ -5,8 +5,8 @@
"plugin": "net.fabricmc.fabric.impl.client.indigo.IndigoMixinConfigPlugin",
"client": [
"BlockModelLighterAccessor",
"ItemFeatureRendererAccessor",
"ItemFeatureRendererMixin"
"FeatureRenderDispatcherMixin",
"ItemFeatureRendererAccessor"
],
"injectors": {
"defaultRequire": 1

View file

@ -49,15 +49,15 @@ include 'fabric-lifecycle-events-v1'
include 'fabric-loot-api-v3'
include 'fabric-menu-api-v1'
include 'fabric-message-api-v1'
//include 'fabric-model-loading-api-v1'
include 'fabric-model-loading-api-v1'
include 'fabric-networking-api-v1'
include 'fabric-object-builder-api-v1'
include 'fabric-particles-v1'
include 'fabric-permission-api-v1'
include 'fabric-recipe-api-v1'
include 'fabric-registry-sync-v0'
//include 'fabric-renderer-api-v1'
//include 'fabric-renderer-indigo'
include 'fabric-renderer-api-v1'
include 'fabric-renderer-indigo'
include 'fabric-rendering-fluids-v1'
include 'fabric-rendering-v1'
include 'fabric-resource-conditions-api-v1'