diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/Renderer.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/Renderer.java index 1ff1b602fc..5d0744c958 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/Renderer.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/Renderer.java @@ -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. * - *

Renderers must patch {@link ItemFeatureRenderer} to support - * {@link FabricSubmitNodeCollection#getExtendedItemSubmits()}. {@link BlockModelFeatureRenderer} is automatically patched - * to support {@link FabricSubmitNodeCollection#getExtendedBlockModelSubmits()} and {@link BlockStateModel#emitQuads}. + *

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 { /** diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricOrderedSubmitNodeCollector.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricOrderedSubmitNodeCollector.java index 7de6d25f56..af3dee3f5f 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricOrderedSubmitNodeCollector.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricOrderedSubmitNodeCollector.java @@ -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 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 diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricSubmitNodeCollection.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricSubmitNodeCollection.java deleted file mode 100644 index 29496f2f19..0000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricSubmitNodeCollection.java +++ /dev/null @@ -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 getExtendedBlockModelSubmits() { - throw new UnsupportedOperationException("Implemented via Mixin."); - } - - /** - * @return {@linkplain ExtendedItemSubmit extended item submits} in this - * {@link SubmitNodeCollection}. - */ - default List 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 renderTypeFunction, boolean translucent, List 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 quads, MeshView mesh, ItemStackRenderState.FoilType foilType) { - } - - // CHECKSTYLE:ON MatchXpath -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/submit/ExtendedBlockModelSubmit.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/submit/ExtendedBlockModelSubmit.java new file mode 100644 index 0000000000..aea65fb23a --- /dev/null +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/submit/ExtendedBlockModelSubmit.java @@ -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 renderTypeFunction, + List 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 TYPE = FeatureRendererType.create("Extended Block Model"); + + @Override + public float distanceToCameraSq() { + return TranslucentSubmit.computeDistanceToCameraSq(pose.pose(), 0.5F, 0.5F, 0.5F); + } + + @Override + public FeatureRendererType featureType() { + return TYPE; + } +} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/submit/ExtendedItemSubmit.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/submit/ExtendedItemSubmit.java new file mode 100644 index 0000000000..98cb6fde59 --- /dev/null +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/submit/ExtendedItemSubmit.java @@ -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 quads, MeshView mesh, + ItemStackRenderState.FoilType foilType) implements TranslucentSubmit { + //CHECKSTYLE.ON: MatchXpath + public static final FeatureRendererType TYPE = FeatureRendererType.create("Extended Item"); + + public boolean hasTranslucency() { + for (BakedQuad quad : quads()) { + if (quad.materialInfo().itemRenderType().hasBlending()) { + return true; + } + } + + var quadInspector = new Consumer() { + 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 featureType() { + return TYPE; + } +} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/BlockModelBufferCache.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/BlockModelBufferCache.java deleted file mode 100644 index 8d1cef634d..0000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/BlockModelBufferCache.java +++ /dev/null @@ -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; - } - } -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/MovingBlockQuadConsumer.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/MovingBlockQuadConsumer.java new file mode 100644 index 0000000000..69a3f2a9fe --- /dev/null +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/MovingBlockQuadConsumer.java @@ -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 { + protected int outlineColor; + + public void outlineColor(int outlineColor) { + this.outlineColor = outlineColor; + } +} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/QuadConsumers.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/QuadConsumers.java deleted file mode 100644 index 7f7ceeca0a..0000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/QuadConsumers.java +++ /dev/null @@ -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 { - public int[] tintLayers; - public int lightCoords; - public int overlayCoords; - public PoseStack.Pose pose; - public Function 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 { - 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); - } - } -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/SimpleModelWrapperMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/SimpleModelWrapperMixin.java index 567d9638a0..163e5a6797 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/SimpleModelWrapperMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/SimpleModelWrapperMixin.java @@ -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 cir, @Local(name = "geometry") QuadCollection geometry, @Local(name = "forbiddenSprites") LocalRef> forbiddenSpritesRef) { + @Unique + private static final ScopedValue 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 storeModelBakery(QuadCollection geometry, Operation> 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> cir, @Local(name = "forbiddenSprites") LocalRef> 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) { diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/BlockModelFeatureRendererMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/BlockModelFeatureRendererMixin.java deleted file mode 100644 index 874247c7f9..0000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/BlockModelFeatureRendererMixin.java +++ /dev/null @@ -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 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 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); - } - } - } - } -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/LevelRendererMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/LevelRendererMixin.java new file mode 100644 index 0000000000..b4d8dd861b --- /dev/null +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/LevelRendererMixin.java @@ -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.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 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 parts, int progress, @Local(name = "random") RandomSource random, @Local(name = "state") BlockBreakingRenderState state, @Local(name = "model") BlockStateModel model, @Share("mutableMesh") LocalRef 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); + } +} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/MovingBlockFeatureRendererMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/MovingBlockFeatureRendererMixin.java index ba2bc90d5c..6d2cd85972 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/MovingBlockFeatureRendererMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/MovingBlockFeatureRendererMixin.java @@ -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.(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 altBlockRenderer, @Share("altQuadOutput") LocalRef 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 { + @Shadow + @Final + private PoseStack poseStack; + + @Inject(method = "buildGroup", at = @At(value = "INVOKE", target = "net/minecraft/client/renderer/block/ModelBlockRenderer.(ZZLnet/minecraft/client/color/block/BlockColors;)V")) + private void beforeInitBlockRenderer(FeatureFrameContext context, List submits, CallbackInfo ci, @Share("altBlockRenderer") LocalRef altBlockRenderer, @Share("altQuadOutput") LocalRef altQuadOutput, @Share("quadConsumer") LocalRef 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 altBlockRenderer, @Share("altQuadOutput") LocalRef 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 altBlockRenderer, @Share("altQuadOutput") LocalRef altQuadOutput, @Share("quadConsumer") LocalRef quadConsumer) { + quadConsumer.get().outlineColor(submit.outlineColor()); altBlockRenderer.get().tesselateBlock(altQuadOutput.get(), x, y, z, level, pos, blockState, model, seed); } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/MaterialBakerMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/MaterialBakerMixin.java index 7902454ae3..dbcc594856 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/MaterialBakerMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/MaterialBakerMixin.java @@ -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 { } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/ModelManagerBlockOnlyMaterialBakerMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/ModelManagerBlockOnlyMaterialBakerMixin.java new file mode 100644 index 0000000000..71c65149cd --- /dev/null +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/ModelManagerBlockOnlyMaterialBakerMixin.java @@ -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; + } +} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/ModelManagerMaterialBakerImplMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/ModelManagerCombinedBlockItemMaterialBakerMixin.java similarity index 88% rename from fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/ModelManagerMaterialBakerImplMixin.java rename to fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/ModelManagerCombinedBlockItemMaterialBakerMixin.java index f833d3f950..c8a37c98da 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/ModelManagerMaterialBakerImplMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/ModelManagerCombinedBlockItemMaterialBakerMixin.java @@ -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()); } } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/submit/SubmitNodeCollectionMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/submit/SubmitNodeCollectionMixin.java index 430d3278af..20f999acc8 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/submit/SubmitNodeCollectionMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/submit/SubmitNodeCollectionMixin.java @@ -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 extendedBlockModelSubmits = new ArrayList<>(); - @Unique - private final List extendedItemSubmits = new ArrayList<>(); + @Shadow + @Nullable + private static RenderType getOutlineRenderType(RenderType renderType) { + return null; + } @Override public void submitBlockModel(PoseStack poseStack, Function renderTypeFunction, boolean translucent, List 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 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 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 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 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 getExtendedBlockModelSubmits() { - return extendedBlockModelSubmits; - } - - @Override - public List 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); } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/submit/SubmitNodeStorageMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/submit/SubmitNodeStorageMixin.java index f080fb5727..f7a8d49f4a 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/submit/SubmitNodeStorageMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/submit/SubmitNodeStorageMixin.java @@ -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 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 quads, MeshView mesh, ItemStackRenderState.FoilType foilType) { order(0).submitItem(poseStack, displayContext, lightCoords, overlayCoords, outlineColor, tintLayers, quads, mesh, foilType); diff --git a/fabric-renderer-api-v1/src/client/resources/fabric-renderer-api-v1.classtweaker b/fabric-renderer-api-v1/src/client/resources/fabric-renderer-api-v1.classtweaker index 54b6151ded..2fd11c2300 100644 --- a/fabric-renderer-api-v1/src/client/resources/fabric-renderer-api-v1.classtweaker +++ b/fabric-renderer-api-v1/src/client/resources/fabric-renderer-api-v1.classtweaker @@ -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 (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 diff --git a/fabric-renderer-api-v1/src/client/resources/fabric-renderer-api-v1.mixins.json b/fabric-renderer-api-v1/src/client/resources/fabric-renderer-api-v1.mixins.json index 436d111177..864856e278 100644 --- a/fabric-renderer-api-v1/src/client/resources/fabric-renderer-api-v1.mixins.json +++ b/fabric-renderer-api-v1/src/client/resources/fabric-renderer-api-v1.mixins.json @@ -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", diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/Indigo.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/Indigo.java index a287bf40bc..c5c4879bf9 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/Indigo.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/Indigo.java @@ -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 LEVEL_RENDERER_BUFFER_SOURCE = ScopedValue.newInstance(); - private static boolean asBoolean(@Nullable String property, boolean defValue) { return asTriState(property).orElse(defValue); } diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/AltItemRenderer.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/AltItemRenderer.java deleted file mode 100644 index 9244da7889..0000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/AltItemRenderer.java +++ /dev/null @@ -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 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]); - } - } -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/ExtendedBlockModelFeatureRenderer.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/ExtendedBlockModelFeatureRenderer.java new file mode 100644 index 0000000000..95c5b4614f --- /dev/null +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/ExtendedBlockModelFeatureRenderer.java @@ -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 { + 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 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 renderTypeFunction; + private PoseStack.@Nullable Pose sheetedDecalPose; + + @Nullable + private ChunkSectionLayer lastLayer; + @Nullable + private VertexConsumer lastBuffer; + + public void prepare(Function 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; + } + } +} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/ExtendedItemFeatureRenderer.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/ExtendedItemFeatureRenderer.java new file mode 100644 index 0000000000..1700327633 --- /dev/null +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/ExtendedItemFeatureRenderer.java @@ -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 { + 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 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 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 + } +} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/FeatureRenderDispatcherMixin.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/FeatureRenderDispatcherMixin.java new file mode 100644 index 0000000000..a68891ba6a --- /dev/null +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/FeatureRenderDispatcherMixin.java @@ -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 = "", at = @At("RETURN")) + private void registerExtendedFeatureRenderers(CallbackInfo ci) { + featureRenderers.put( + ExtendedBlockModelSubmit.TYPE, + new ExtendedBlockModelFeatureRenderer() + ); + featureRenderers.put( + ExtendedItemSubmit.TYPE, + new ExtendedItemFeatureRenderer() + ); + } +} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemFeatureRendererAccessor.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemFeatureRendererAccessor.java index 3880bd58c0..fdfff08d9f 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemFeatureRendererAccessor.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemFeatureRendererAccessor.java @@ -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(); + } } diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemFeatureRendererMixin.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemFeatureRendererMixin.java deleted file mode 100644 index e113625001..0000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemFeatureRendererMixin.java +++ /dev/null @@ -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(); - } -} diff --git a/fabric-renderer-indigo/src/client/resources/fabric-renderer-indigo.mixins.json b/fabric-renderer-indigo/src/client/resources/fabric-renderer-indigo.mixins.json index 90b0804e1e..a5d2665a3d 100644 --- a/fabric-renderer-indigo/src/client/resources/fabric-renderer-indigo.mixins.json +++ b/fabric-renderer-indigo/src/client/resources/fabric-renderer-indigo.mixins.json @@ -5,8 +5,8 @@ "plugin": "net.fabricmc.fabric.impl.client.indigo.IndigoMixinConfigPlugin", "client": [ "BlockModelLighterAccessor", - "ItemFeatureRendererAccessor", - "ItemFeatureRendererMixin" + "FeatureRenderDispatcherMixin", + "ItemFeatureRendererAccessor" ], "injectors": { "defaultRequire": 1 diff --git a/settings.gradle b/settings.gradle index 0d3748dc6b..d505287a62 100644 --- a/settings.gradle +++ b/settings.gradle @@ -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'