FRAPI improvements: context getters, full removal of fallback consumers, small enhancements (#3287)

* Add cull check and item transformation mode getter to FRAPI

* Terminally deprecate `fallbackConsumer` and `bakedModelConsumer`

* Fix uvs in octagonal column test mod

* Review comments
This commit is contained in:
Technici4n 2023-09-18 17:13:11 +02:00 committed by GitHub
parent ecfd5a888d
commit 39a511ba53
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 255 additions and 134 deletions

View file

@ -29,6 +29,7 @@ import net.minecraft.util.math.random.Random;
import net.minecraft.world.BlockRenderView;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.fabricmc.fabric.impl.renderer.VanillaModelEncoder;
/**
* Interface for baked models that output meshes with enhanced rendering features.
@ -92,9 +93,8 @@ public interface FabricBakedModel {
* Will not be thread-safe. Do not cache or retain a reference.
* @param context Accepts model output.
*/
@SuppressWarnings("deprecation")
default void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
context.bakedModelConsumer().accept((BakedModel) this, state);
VanillaModelEncoder.emitBlockQuads((BakedModel) this, state, randomSupplier, context, context.getEmitter());
}
/**
@ -124,9 +124,7 @@ public interface FabricBakedModel {
* logic here, instead of returning every possible shape from {@link BakedModel#getOverrides}
* as vanilla baked models.
*/
@SuppressWarnings("deprecation")
default void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
// Pass null state to enforce item quads in block render contexts
context.bakedModelConsumer().accept((BakedModel) this, null);
VanillaModelEncoder.emitItemQuads((BakedModel) this, null, randomSupplier, context);
}
}

View file

@ -23,13 +23,16 @@ import org.jetbrains.annotations.Nullable;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockRenderView;
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
/**
@ -54,6 +57,15 @@ public interface RenderContext {
*/
QuadEmitter getEmitter();
/**
* Returns whether this context currently has at least one transform.
*
* @apiNote The default implementation will be removed in the next breaking release.
*/
default boolean hasTransform() {
return true;
}
/**
* Causes all models/quads/meshes sent to this consumer to be transformed by the provided
* {@link QuadTransform} that edits each quad before buffering. Quads in the mesh will
@ -67,6 +79,8 @@ public interface RenderContext {
*
* <p>Meshes are never mutated by the transformer - only buffered quads. This ensures thread-safe
* use of meshes/models across multiple chunk builders.
*
* <p>Using the {@linkplain #getEmitter() quad emitter of this context} from the inside of a quad transform is not supported.
*/
void pushTransform(QuadTransform transform);
@ -76,6 +90,36 @@ public interface RenderContext {
*/
void popTransform();
/**
* Returns {@code true} if the given face will be culled away.
*
* <p>This function can be used to skip complex transformations of quads that will be culled anyway.
* The cull face of a quad is determined by {@link QuadView#cullFace()}.
* Note that if {@linkplain #hasTransform() there is a transform}, no computation should be skipped,
* because the cull face might be changed by the transform,
* or the transform might wish to receive culled faces too.
*
* <p>This function can only be used on a block render context (i.e. in {@link FabricBakedModel#emitBlockQuads}).
* Calling it on another context (e.g. in {@link FabricBakedModel#emitItemQuads}) will throw an exception.
*
* @apiNote The default implementation will be removed in the next breaking release.
*/
default boolean isFaceCulled(@Nullable Direction face) {
return false;
}
/**
* Returns the current transformation mode.
*
* <p>This function can only be used on an item render context (i.e. in {@link FabricBakedModel#emitItemQuads}).
* Calling it on another context (e.g. in {@link FabricBakedModel#emitBlockQuads}) will throw an exception.
*
* @apiNote The default implementation will be removed in the next breaking release.
*/
default ModelTransformationMode itemTransformationMode() {
return ModelTransformationMode.NONE;
}
@FunctionalInterface
interface QuadTransform {
/**
@ -89,14 +133,16 @@ public interface RenderContext {
* @deprecated Use {@link Mesh#outputTo(QuadEmitter)} instead.
*/
@Deprecated
Consumer<Mesh> meshConsumer();
default Consumer<Mesh> meshConsumer() {
return mesh -> mesh.outputTo(getEmitter());
}
/**
* @deprecated Use {@link FabricBakedModel#emitBlockQuads(BlockRenderView, BlockState, BlockPos, Supplier, RenderContext) emitBlockQuads}
* or {@link FabricBakedModel#emitItemQuads(ItemStack, Supplier, RenderContext) emitItemQuads} on the baked model
* that you want to consume instead.
*/
@Deprecated
@Deprecated(forRemoval = true)
BakedModelConsumer bakedModelConsumer();
/**
@ -104,12 +150,12 @@ public interface RenderContext {
* or {@link FabricBakedModel#emitItemQuads(ItemStack, Supplier, RenderContext) emitItemQuads} on the baked model
* that you want to consume instead.
*/
@Deprecated
@Deprecated(forRemoval = true)
default Consumer<BakedModel> fallbackConsumer() {
return bakedModelConsumer();
}
@Deprecated
@Deprecated(forRemoval = true)
interface BakedModelConsumer extends Consumer<BakedModel> {
/**
* Render a baked model by processing its {@linkplain BakedModel#getQuads} using the rendered block state.

View file

@ -0,0 +1,85 @@
/*
* 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.renderer;
import java.util.List;
import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.random.Random;
import net.fabricmc.fabric.api.renderer.v1.Renderer;
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.fabricmc.fabric.api.util.TriState;
/**
* Routines for adaptation of vanilla {@link BakedModel}s to FRAPI pipelines.
* Even though Indigo calls them directly, they are not for use by third party renderers, and might change at any time.
*/
public class VanillaModelEncoder {
private static final Renderer RENDERER = RendererAccess.INSTANCE.getRenderer();
private static final RenderMaterial MATERIAL_STANDARD = RENDERER.materialFinder().find();
private static final RenderMaterial MATERIAL_NO_AO = RENDERER.materialFinder().ambientOcclusion(TriState.FALSE).find();
// Separate QuadEmitter parameter so that Indigo can pass its own emitter that handles vanilla quads differently.
public static void emitBlockQuads(BakedModel model, @Nullable BlockState state, Supplier<Random> randomSupplier, RenderContext context, QuadEmitter emitter) {
final RenderMaterial defaultMaterial = model.useAmbientOcclusion() ? MATERIAL_STANDARD : MATERIAL_NO_AO;
for (int i = 0; i <= ModelHelper.NULL_FACE_ID; i++) {
final Direction cullFace = ModelHelper.faceFromIndex(i);
if (!context.hasTransform() && context.isFaceCulled(cullFace)) {
// Skip entire quad list if possible.
continue;
}
final List<BakedQuad> quads = model.getQuads(state, cullFace, randomSupplier.get());
final int count = quads.size();
for (int j = 0; j < count; j++) {
final BakedQuad q = quads.get(j);
emitter.fromVanilla(q, defaultMaterial, cullFace);
emitter.emit();
}
}
}
public static void emitItemQuads(BakedModel model, @Nullable BlockState state, Supplier<Random> randomSupplier, RenderContext context) {
QuadEmitter emitter = context.getEmitter();
for (int i = 0; i <= ModelHelper.NULL_FACE_ID; i++) {
final Direction cullFace = ModelHelper.faceFromIndex(i);
final List<BakedQuad> quads = model.getQuads(state, cullFace, randomSupplier.get());
final int count = quads.size();
for (int j = 0; j < count; j++) {
final BakedQuad q = quads.get(j);
emitter.fromVanilla(q, MATERIAL_STANDARD, cullFace);
emitter.emit();
}
}
}
}

View file

@ -30,6 +30,7 @@ import net.minecraft.client.texture.Sprite;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Direction;
import net.fabricmc.fabric.api.renderer.v1.Renderer;
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
@ -79,6 +80,7 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
emitter.pos(1, 0.5f, 1, 0.5f);
emitter.pos(2, 1, 1, A);
emitter.pos(3, B, 1, 0);
emitter.cullFace(Direction.UP);
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
emitter.color(-1, -1, -1, -1);
emitter.emit();
@ -87,6 +89,7 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
emitter.pos(1, 0, 1, B);
emitter.pos(2, 0.5f, 1, 0.5f);
emitter.pos(3, A, 1, 0);
emitter.cullFace(Direction.UP);
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
emitter.color(-1, -1, -1, -1);
emitter.emit();
@ -95,6 +98,7 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
emitter.pos(1, A, 1, 1);
emitter.pos(2, B, 1, 1);
emitter.pos(3, 0.5f, 1, 0.5f);
emitter.cullFace(Direction.UP);
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
emitter.color(-1, -1, -1, -1);
emitter.emit();
@ -103,6 +107,7 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
emitter.pos(1, B, 1, 1);
emitter.pos(2, 1, 1, B);
emitter.pos(3, 1, 1, A);
emitter.cullFace(Direction.UP);
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
emitter.color(-1, -1, -1, -1);
emitter.emit();
@ -113,6 +118,7 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
emitter.pos(1, 0.5f, 0, 0.5f);
emitter.pos(2, 1, 0, B);
emitter.pos(3, B, 0, 1);
emitter.cullFace(Direction.DOWN);
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
emitter.color(-1, -1, -1, -1);
emitter.emit();
@ -121,6 +127,7 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
emitter.pos(1, 0, 0, A);
emitter.pos(2, 0.5f, 0, 0.5f);
emitter.pos(3, A, 0, 1);
emitter.cullFace(Direction.DOWN);
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
emitter.color(-1, -1, -1, -1);
emitter.emit();
@ -129,6 +136,7 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
emitter.pos(1, A, 0, 0);
emitter.pos(2, B, 0, 0);
emitter.pos(3, 0.5f, 0, 0.5f);
emitter.cullFace(Direction.DOWN);
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
emitter.color(-1, -1, -1, -1);
emitter.emit();
@ -137,6 +145,7 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
emitter.pos(1, B, 0, 0);
emitter.pos(2, 1, 0, A);
emitter.pos(3, 1, 0, B);
emitter.cullFace(Direction.DOWN);
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
emitter.color(-1, -1, -1, -1);
emitter.emit();
@ -146,6 +155,7 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
emitter.pos(1, B, 0, 0);
emitter.pos(2, A, 0, 0);
emitter.pos(3, A, 1, 0);
emitter.cullFace(Direction.NORTH);
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
emitter.material(glintMaterial);
emitter.color(-1, -1, -1, -1);
@ -156,7 +166,7 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
emitter.pos(1, A, 0, 0);
emitter.pos(2, 0, 0, A);
emitter.pos(3, 0, 1, A);
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
cornerSprite(emitter, whiteConcreteSprite);
emitter.material(glintMaterial);
emitter.color(-1, -1, -1, -1);
emitter.emit();
@ -166,6 +176,7 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
emitter.pos(1, 0, 0, A);
emitter.pos(2, 0, 0, B);
emitter.pos(3, 0, 1, B);
emitter.cullFace(Direction.WEST);
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
emitter.material(glintMaterial);
emitter.color(-1, -1, -1, -1);
@ -176,7 +187,7 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
emitter.pos(1, 0, 0, B);
emitter.pos(2, A, 0, 1);
emitter.pos(3, A, 1, 1);
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
cornerSprite(emitter, whiteConcreteSprite);
emitter.material(glintMaterial);
emitter.color(-1, -1, -1, -1);
emitter.emit();
@ -186,6 +197,7 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
emitter.pos(1, A, 0, 1);
emitter.pos(2, B, 0, 1);
emitter.pos(3, B, 1, 1);
emitter.cullFace(Direction.SOUTH);
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
emitter.material(glintMaterial);
emitter.color(-1, -1, -1, -1);
@ -196,7 +208,7 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
emitter.pos(1, B, 0, 1);
emitter.pos(2, 1, 0, B);
emitter.pos(3, 1, 1, B);
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
cornerSprite(emitter, whiteConcreteSprite);
emitter.material(glintMaterial);
emitter.color(-1, -1, -1, -1);
emitter.emit();
@ -206,6 +218,7 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
emitter.pos(1, 1, 0, B);
emitter.pos(2, 1, 0, A);
emitter.pos(3, 1, 1, A);
emitter.cullFace(Direction.EAST);
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
emitter.material(glintMaterial);
emitter.color(-1, -1, -1, -1);
@ -216,11 +229,21 @@ public class OctagonalColumnUnbakedModel implements UnbakedModel {
emitter.pos(1, 1, 0, A);
emitter.pos(2, B, 0, 0);
emitter.pos(3, B, 1, 0);
emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV);
cornerSprite(emitter, whiteConcreteSprite);
emitter.material(glintMaterial);
emitter.color(-1, -1, -1, -1);
emitter.emit();
return new SingleMeshBakedModel(builder.build(), whiteConcreteSprite);
}
private static void cornerSprite(QuadEmitter emitter, Sprite sprite) {
// Assign uvs for a corner face in such a way that the texture is not stretched, using coordinates in [0, 1].
emitter.uv(0, A, 0);
emitter.uv(1, A, 1);
emitter.uv(2, B, 1);
emitter.uv(3, B, 0);
// Map [0, 1] coordinates to sprite atlas coordinates. spriteBake assumes [0, 16] unless we pass the BAKE_NORMALIZED flag.
emitter.spriteBake(sprite, MutableQuadView.BAKE_NORMALIZED);
}
}

View file

@ -19,8 +19,6 @@ package net.fabricmc.fabric.impl.client.indigo.renderer.render;
import static net.fabricmc.fabric.impl.client.indigo.renderer.helper.GeometryHelper.AXIS_ALIGNED_FLAG;
import static net.fabricmc.fabric.impl.client.indigo.renderer.helper.GeometryHelper.LIGHT_FACE_FLAG;
import java.util.List;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
@ -30,21 +28,20 @@ import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.WorldRenderer;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
import net.fabricmc.fabric.api.util.TriState;
import net.fabricmc.fabric.impl.client.indigo.Indigo;
import net.fabricmc.fabric.impl.client.indigo.renderer.IndigoRenderer;
import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.AoCalculator;
import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.AoConfig;
import net.fabricmc.fabric.impl.client.indigo.renderer.helper.ColorHelper;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.EncodingFormat;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl;
import net.fabricmc.fabric.impl.renderer.VanillaModelEncoder;
public abstract class AbstractBlockRenderContext extends AbstractRenderContext {
protected final BlockRenderInfo blockInfo = new BlockRenderInfo();
@ -61,6 +58,17 @@ public abstract class AbstractBlockRenderContext extends AbstractRenderContext {
renderQuad(this, false);
}
};
private final MutableQuadViewImpl vanillaModelEditorQuad = new MutableQuadViewImpl() {
{
data = new int[EncodingFormat.TOTAL_STRIDE];
clear();
}
@Override
public void emitDirectly() {
renderQuad(this, true);
}
};
private final BakedModelConsumerImpl vanillaModelConsumer = new BakedModelConsumerImpl();
@ -80,6 +88,21 @@ public abstract class AbstractBlockRenderContext extends AbstractRenderContext {
return editorQuad;
}
public QuadEmitter getVanillaModelEmitter() {
// Do not clear the editorQuad since it is not accessible to API users.
return vanillaModelEditorQuad;
}
@Override
public boolean isFaceCulled(@Nullable Direction face) {
return !blockInfo.shouldDrawFace(face);
}
@Override
public ModelTransformationMode itemTransformationMode() {
throw new IllegalStateException("itemTransformationMode() can only be called on an item render context.");
}
@Override
public BakedModelConsumer bakedModelConsumer() {
return vanillaModelConsumer;
@ -90,7 +113,7 @@ public abstract class AbstractBlockRenderContext extends AbstractRenderContext {
return;
}
if (!blockInfo.shouldDrawFace(quad.cullFace())) {
if (isFaceCulled(quad.cullFace())) {
return;
}
@ -275,21 +298,6 @@ public abstract class AbstractBlockRenderContext extends AbstractRenderContext {
* them through vanilla logic would require additional hooks.
*/
private class BakedModelConsumerImpl implements BakedModelConsumer {
private static final RenderMaterial MATERIAL_SHADED = IndigoRenderer.INSTANCE.materialFinder().find();
private static final RenderMaterial MATERIAL_FLAT = IndigoRenderer.INSTANCE.materialFinder().ambientOcclusion(TriState.FALSE).find();
private final MutableQuadViewImpl editorQuad = new MutableQuadViewImpl() {
{
data = new int[EncodingFormat.TOTAL_STRIDE];
clear();
}
@Override
public void emitDirectly() {
renderQuad(this, true);
}
};
@Override
public void accept(BakedModel model) {
accept(model, blockInfo.blockState);
@ -297,23 +305,7 @@ public abstract class AbstractBlockRenderContext extends AbstractRenderContext {
@Override
public void accept(BakedModel model, @Nullable BlockState state) {
MutableQuadViewImpl editorQuad = this.editorQuad;
final RenderMaterial defaultMaterial = model.useAmbientOcclusion() ? MATERIAL_SHADED : MATERIAL_FLAT;
for (int i = 0; i <= ModelHelper.NULL_FACE_ID; i++) {
final Direction cullFace = ModelHelper.faceFromIndex(i);
final List<BakedQuad> quads = model.getQuads(state, cullFace, blockInfo.randomSupplier.get());
final int count = quads.size();
for (int j = 0; j < count; j++) {
final BakedQuad q = quads.get(j);
editorQuad.fromVanilla(q, defaultMaterial, cullFace);
// Call renderQuad directly instead of emit for efficiency
renderQuad(editorQuad, true);
}
}
// Do not clear the editorQuad since it is not accessible to API users.
VanillaModelEncoder.emitBlockQuads(model, state, blockInfo.randomSupplier, AbstractBlockRenderContext.this, vanillaModelEditorQuad);
}
}
}

View file

@ -61,7 +61,8 @@ abstract class AbstractRenderContext implements RenderContext {
return activeTransform.transform(q);
}
protected boolean hasTransform() {
@Override
public boolean hasTransform() {
return activeTransform != NO_TRANSFORM;
}

View file

@ -1,36 +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 net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.ItemStack;
public class IndigoQuadHandler implements ItemRenderContext.VanillaQuadHandler {
private final ItemRenderer itemRenderer;
public IndigoQuadHandler(ItemRenderer itemRenderer) {
this.itemRenderer = itemRenderer;
}
@Override
public void accept(BakedModel model, ItemStack stack, int color, int overlay, MatrixStack matrixStack, VertexConsumer buffer) {
itemRenderer.renderBakedItemModel(model, stack, color, overlay, matrixStack, buffer);
}
}

View file

@ -16,7 +16,6 @@
package net.fabricmc.fabric.impl.client.indigo.renderer.render;
import java.util.List;
import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable;
@ -32,7 +31,6 @@ import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.BlockItem;
@ -44,12 +42,11 @@ import net.minecraft.util.math.random.Random;
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
import net.fabricmc.fabric.api.util.TriState;
import net.fabricmc.fabric.impl.client.indigo.renderer.IndigoRenderer;
import net.fabricmc.fabric.impl.client.indigo.renderer.helper.ColorHelper;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.EncodingFormat;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl;
import net.fabricmc.fabric.impl.renderer.VanillaModelEncoder;
/**
* The render context used for item rendering.
@ -84,7 +81,6 @@ public class ItemRenderContext extends AbstractRenderContext {
private MatrixStack matrixStack;
private VertexConsumerProvider vertexConsumerProvider;
private int lightmap;
private VanillaQuadHandler vanillaHandler;
private boolean isDefaultTranslucent;
private boolean isTranslucentDirect;
@ -94,7 +90,6 @@ public class ItemRenderContext extends AbstractRenderContext {
private VertexConsumer cutoutVertexConsumer;
private VertexConsumer translucentGlintVertexConsumer;
private VertexConsumer cutoutGlintVertexConsumer;
private VertexConsumer defaultVertexConsumer;
public ItemRenderContext(ItemColors colorMap) {
this.colorMap = colorMap;
@ -106,19 +101,28 @@ public class ItemRenderContext extends AbstractRenderContext {
return editorQuad;
}
@Override
public boolean isFaceCulled(@Nullable Direction face) {
throw new IllegalStateException("isFaceCulled can only be called on a block render context.");
}
@Override
public ModelTransformationMode itemTransformationMode() {
return transformMode;
}
@Override
public BakedModelConsumer bakedModelConsumer() {
return vanillaModelConsumer;
}
public void renderModel(ItemStack itemStack, ModelTransformationMode transformMode, boolean invert, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int lightmap, int overlay, BakedModel model, VanillaQuadHandler vanillaHandler) {
public void renderModel(ItemStack itemStack, ModelTransformationMode transformMode, boolean invert, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int lightmap, int overlay, BakedModel model) {
this.itemStack = itemStack;
this.transformMode = transformMode;
this.matrixStack = matrixStack;
this.vertexConsumerProvider = vertexConsumerProvider;
this.lightmap = lightmap;
this.overlay = overlay;
this.vanillaHandler = vanillaHandler;
computeOutputInfo();
matrix = matrixStack.peek().getPositionMatrix();
@ -129,13 +133,11 @@ public class ItemRenderContext extends AbstractRenderContext {
this.itemStack = null;
this.matrixStack = null;
this.vertexConsumerProvider = null;
this.vanillaHandler = null;
translucentVertexConsumer = null;
cutoutVertexConsumer = null;
translucentGlintVertexConsumer = null;
cutoutGlintVertexConsumer = null;
defaultVertexConsumer = null;
}
private void computeOutputInfo() {
@ -158,8 +160,6 @@ public class ItemRenderContext extends AbstractRenderContext {
}
isDefaultGlint = itemStack.hasGlint();
defaultVertexConsumer = getVertexConsumer(BlendMode.DEFAULT, TriState.DEFAULT);
}
private void renderQuad(MutableQuadViewImpl quad) {
@ -275,34 +275,7 @@ public class ItemRenderContext extends AbstractRenderContext {
@Override
public void accept(BakedModel model, @Nullable BlockState state) {
if (hasTransform()) {
MutableQuadViewImpl editorQuad = ItemRenderContext.this.editorQuad;
// if there's a transform in effect, convert to mesh-based quads so that we can apply it
for (int i = 0; i <= ModelHelper.NULL_FACE_ID; i++) {
final Direction cullFace = ModelHelper.faceFromIndex(i);
random.setSeed(ITEM_RANDOM_SEED);
final List<BakedQuad> quads = model.getQuads(state, cullFace, random);
final int count = quads.size();
for (int j = 0; j < count; j++) {
final BakedQuad q = quads.get(j);
editorQuad.fromVanilla(q, IndigoRenderer.MATERIAL_STANDARD, cullFace);
// Call renderQuad directly instead of emit for efficiency
renderQuad(editorQuad);
}
}
editorQuad.clear();
} else {
vanillaHandler.accept(model, itemStack, lightmap, overlay, matrixStack, defaultVertexConsumer);
}
VanillaModelEncoder.emitItemQuads(model, state, randomSupplier, ItemRenderContext.this);
}
}
/** used to accept a method reference from the ItemRenderer. */
@FunctionalInterface
public interface VanillaQuadHandler {
void accept(BakedModel model, ItemStack stack, int color, int overlay, MatrixStack matrixStack, VertexConsumer buffer);
}
}

View file

@ -0,0 +1,43 @@
/*
* 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 java.util.function.Supplier;
import org.spongepowered.asm.mixin.Mixin;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.BlockRenderView;
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.fabricmc.fabric.impl.client.indigo.renderer.render.AbstractBlockRenderContext;
import net.fabricmc.fabric.impl.renderer.VanillaModelEncoder;
@Mixin(BakedModel.class)
public interface BakedModelMixin extends FabricBakedModel {
/**
* Override the fallback path to shade vanilla quads differently.
*/
@Override
default void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
VanillaModelEncoder.emitBlockQuads((BakedModel) this, state, randomSupplier, context, ((AbstractBlockRenderContext) context).getVanillaModelEmitter());
}
}

View file

@ -32,9 +32,7 @@ import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.ItemStack;
import net.fabricmc.fabric.impl.client.indigo.renderer.render.IndigoQuadHandler;
import net.fabricmc.fabric.impl.client.indigo.renderer.render.ItemRenderContext;
import net.fabricmc.fabric.impl.client.indigo.renderer.render.ItemRenderContext.VanillaQuadHandler;
@Mixin(ItemRenderer.class)
public abstract class ItemRendererMixin {
@ -45,13 +43,10 @@ public abstract class ItemRendererMixin {
@Unique
private final ThreadLocal<ItemRenderContext> fabric_contexts = ThreadLocal.withInitial(() -> new ItemRenderContext(colors));
@Unique
private final VanillaQuadHandler fabric_vanillaHandler = new IndigoQuadHandler((ItemRenderer) (Object) this);
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/BakedModel;isBuiltin()Z"), method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V", cancellable = true)
public void hook_renderItem(ItemStack stack, ModelTransformationMode transformMode, boolean invert, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light, int overlay, BakedModel model, CallbackInfo ci) {
if (!model.isVanillaAdapter()) {
fabric_contexts.get().renderModel(stack, transformMode, invert, matrixStack, vertexConsumerProvider, light, overlay, model, fabric_vanillaHandler);
fabric_contexts.get().renderModel(stack, transformMode, invert, matrixStack, vertexConsumerProvider, light, overlay, model);
matrixStack.pop();
ci.cancel();
}

View file

@ -6,6 +6,7 @@
"mixins": [
],
"client": [
"BakedModelMixin",
"BlockModelRendererMixin",
"ChunkBuilderBuiltChunkRebuildTaskMixin",
"ChunkRendererRegionMixin",