diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/BlockStateResolver.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/BlockStateResolver.java index 9d70e3987d1..934e8c87b31 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/BlockStateResolver.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/BlockStateResolver.java @@ -18,7 +18,7 @@ import org.jetbrains.annotations.ApiStatus; -import net.minecraft.client.renderer.block.model.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/CompositeBlockStateModel.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/CompositeBlockStateModel.java index 15fb6a90535..8872d54488e 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/CompositeBlockStateModel.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/CompositeBlockStateModel.java @@ -21,7 +21,7 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Unmodifiable; -import net.minecraft.client.renderer.block.model.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; import net.minecraft.client.renderer.item.CompositeModel; import net.fabricmc.fabric.impl.client.model.loading.CompositeBlockStateModelImpl; diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/CustomUnbakedBlockStateModel.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/CustomUnbakedBlockStateModel.java index 9b3a397012b..389c2b365b4 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/CustomUnbakedBlockStateModel.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/CustomUnbakedBlockStateModel.java @@ -18,9 +18,9 @@ import com.mojang.serialization.MapCodec; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.block.model.SingleVariant; -import net.minecraft.client.renderer.block.model.Variant; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.SingleVariant; +import net.minecraft.client.renderer.block.dispatch.Variant; import net.minecraft.resources.Identifier; import net.fabricmc.fabric.impl.client.model.loading.CustomUnbakedBlockStateModelRegistry; diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/ModelModifier.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/ModelModifier.java index 65e2fd92237..6196fdb2777 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/ModelModifier.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/ModelModifier.java @@ -17,8 +17,9 @@ package net.fabricmc.fabric.api.client.model.loading.v1; import org.jetbrains.annotations.ApiStatus; +import org.joml.Matrix4fc; -import net.minecraft.client.renderer.block.model.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; import net.minecraft.client.renderer.item.ItemModel; import net.minecraft.client.resources.model.ModelBaker; import net.minecraft.client.resources.model.ResolvableModel; @@ -144,7 +145,7 @@ interface Context { /** * The baker being used to bake this model. It can be used to - * {@linkplain ModelBaker#getModel get resolved models} and {@linkplain ModelBaker#sprites get sprites}. Note + * {@linkplain ModelBaker#getModel get resolved models} and {@linkplain ModelBaker#materials get materials}. Note * that retrieving a model which was not previously * {@linkplain ResolvableModel.Resolver#markDependency discovered} will log a warning and return the missing * model. @@ -182,7 +183,7 @@ interface Context { /** * The baker being used to bake this model. It can be used to - * {@linkplain ModelBaker#getModel get resolved models} and {@linkplain ModelBaker#sprites get sprites}. Note + * {@linkplain ModelBaker#getModel get resolved models} and {@linkplain ModelBaker#materials get materials}. Note * that retrieving a model which was not previously * {@linkplain ResolvableModel.Resolver#markDependency discovered} will log a warning and return the missing * model. @@ -217,6 +218,11 @@ interface Context { * The vanilla context being used to bake this model. */ ItemModel.BakingContext bakingContext(); + + /** + * The transformation applied during baking of this model. + */ + Matrix4fc transformation(); } } @@ -251,6 +257,11 @@ interface Context { * The vanilla context being used to bake this model. */ ItemModel.BakingContext bakingContext(); + + /** + * The transformation applied during baking of this model. + */ + Matrix4fc transformation(); } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/SimpleUnbakedExtraModel.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/SimpleUnbakedExtraModel.java index 7be91f8af58..49bcb04bf29 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/SimpleUnbakedExtraModel.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/SimpleUnbakedExtraModel.java @@ -18,22 +18,39 @@ import java.util.function.BiFunction; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.block.model.SimpleModelWrapper; -import net.minecraft.client.renderer.block.model.SingleVariant; -import net.minecraft.client.renderer.block.model.TextureSlots; -import net.minecraft.client.resources.model.BlockModelRotation; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.mojang.logging.LogUtils; +import org.apache.commons.lang3.mutable.MutableObject; +import org.slf4j.Logger; + +import net.minecraft.client.renderer.block.dispatch.BlockModelRotation; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart; +import net.minecraft.client.renderer.block.dispatch.ModelState; +import net.minecraft.client.renderer.block.dispatch.SingleVariant; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.ModelBaker; -import net.minecraft.client.resources.model.ModelState; import net.minecraft.client.resources.model.ResolvedModel; +import net.minecraft.client.resources.model.SimpleModelWrapper; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.geometry.QuadCollection; +import net.minecraft.client.resources.model.sprite.Material; +import net.minecraft.client.resources.model.sprite.TextureSlots; import net.minecraft.resources.Identifier; +import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadAtlas; +import net.fabricmc.fabric.api.client.renderer.v1.model.MeshQuadCollection; + /** * A {@link UnbakedExtraModel} that loads a single model. * * @param The type of the baked model, for instance {@link BlockStateModel}. */ public final class SimpleUnbakedExtraModel implements UnbakedExtraModel { + private static final Logger LOGGER = LogUtils.getLogger(); + private final Identifier model; private final BiFunction bake; @@ -69,19 +86,61 @@ public static SimpleUnbakedExtraModel blockStateModel(Identifie /** * Create a {@link SimpleUnbakedExtraModel} for a {@link BlockStateModel}. * - * @param model The location of the model to load. - * @param settings The settings to bake the geometry with. + * @param model The location of the model to load. + * @param state The state to bake the geometry with. * @return The unbaked extra model. */ - public static SimpleUnbakedExtraModel blockStateModel(Identifier model, ModelState settings) { - return new SimpleUnbakedExtraModel<>(model, (baked, baker) -> { - TextureSlots textures = baked.getTopTextureSlots(); - return new SingleVariant(new SimpleModelWrapper( - baked.bakeTopGeometry(textures, baker, settings), - baked.getTopAmbientOcclusion(), - baked.resolveParticleSprite(textures, baker) - )); - }); + public static SimpleUnbakedExtraModel blockStateModel(Identifier model, ModelState state) { + return new SimpleUnbakedExtraModel<>(model, (baked, baker) -> new SingleVariant(bakeResolved(baker, baked, state))); + } + + // TODO: expose this as a public utility + // Mirror of SimpleModelWrapper#bake (with FRAPI's mixin) that accepts a ResolvedModel instead of an Identifier + private static BlockStateModelPart bakeResolved(final ModelBaker modelBakery, final ResolvedModel model, final ModelState state) { + TextureSlots textureSlots = model.getTopTextureSlots(); + boolean hasAmbientOcclusion = model.getTopAmbientOcclusion(); + Material.Baked particleMaterial = model.resolveParticleMaterial(textureSlots, modelBakery); + QuadCollection geometry = model.bakeTopGeometry(textureSlots, modelBakery, state); + Multimap forbiddenSprites = null; + + if (geometry instanceof MeshQuadCollection meshQuadCollection) { + MutableObject> forbiddenSpritesRef = new MutableObject<>(forbiddenSprites); + + meshQuadCollection.getMesh().forEach(quad -> { + if (quad.atlas() != QuadAtlas.BLOCK) { + Multimap forbiddenSprites1 = forbiddenSpritesRef.get(); + + if (forbiddenSprites1 == null) { + forbiddenSprites1 = HashMultimap.create(); + forbiddenSpritesRef.setValue(forbiddenSprites1); + } + + TextureAtlasSprite sprite = modelBakery.materials().spriteFinder(quad.atlas()).find(quad); + forbiddenSprites1.put(sprite.atlasLocation(), sprite.contents().name()); + } + }); + + forbiddenSprites = forbiddenSpritesRef.get(); + } + + for (BakedQuad bakedQuad : geometry.getAll()) { + TextureAtlasSprite sprite = bakedQuad.materialInfo().sprite(); + + if (!sprite.atlasLocation().equals(TextureAtlas.LOCATION_BLOCKS)) { + if (forbiddenSprites == null) { + forbiddenSprites = HashMultimap.create(); + } + + forbiddenSprites.put(sprite.atlasLocation(), sprite.contents().name()); + } + } + + if (forbiddenSprites != null) { + LOGGER.warn("Rejecting block model {}, since it contains sprites from outside of supported atlas: {}", model.debugName(), forbiddenSprites); + return modelBakery.missingBlockModelPart(); + } else { + return new SimpleModelWrapper(geometry, hasAmbientOcclusion, particleMaterial); + } } @Override diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/UnbakedModelDeserializer.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/UnbakedModelDeserializer.java index ef5200e059d..564d03c3977 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/UnbakedModelDeserializer.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/UnbakedModelDeserializer.java @@ -23,12 +23,12 @@ import com.google.gson.JsonParseException; import org.jspecify.annotations.Nullable; -import net.minecraft.client.renderer.block.model.BlockElement; -import net.minecraft.client.renderer.block.model.BlockElementFace; -import net.minecraft.client.renderer.block.model.BlockModel; -import net.minecraft.client.renderer.block.model.ItemTransform; -import net.minecraft.client.renderer.block.model.ItemTransforms; import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.client.resources.model.cuboid.CuboidFace; +import net.minecraft.client.resources.model.cuboid.CuboidModel; +import net.minecraft.client.resources.model.cuboid.CuboidModelElement; +import net.minecraft.client.resources.model.cuboid.ItemTransform; +import net.minecraft.client.resources.model.cuboid.ItemTransforms; import net.minecraft.resources.Identifier; import net.fabricmc.fabric.impl.client.model.loading.UnbakedModelDeserializerRegistry; @@ -74,7 +74,7 @@ static UnbakedModelDeserializer get(Identifier id) { /** * Deserializes an {@link UnbakedModel} from a {@link Reader}, respecting custom deserializers. Prefer using this - * method to {@link BlockModel#fromStream(Reader)}. + * method to {@link CuboidModel#fromStream(Reader)}. */ static UnbakedModel deserialize(Reader reader) throws JsonParseException { return UnbakedModelDeserializerRegistry.deserialize(reader); @@ -86,8 +86,8 @@ static UnbakedModel deserialize(Reader reader) throws JsonParseException { *

The provided deserialization context is able to deserialize objects of the following types: *

    *
  • {@link UnbakedModel}
  • - *
  • {@link BlockElement}
  • - *
  • {@link BlockElementFace}
  • + *
  • {@link CuboidModelElement}
  • + *
  • {@link CuboidFace}
  • *
  • {@link ItemTransform}
  • *
  • {@link ItemTransforms}
  • *
diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/wrapper/WrapperBlockStateModel.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/wrapper/WrapperBlockStateModel.java index bcada8f96df..f46063cec69 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/wrapper/WrapperBlockStateModel.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/wrapper/WrapperBlockStateModel.java @@ -21,13 +21,14 @@ import org.jspecify.annotations.Nullable; -import net.minecraft.client.renderer.block.model.BlockModelPart; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; +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.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter; @@ -47,18 +48,23 @@ protected WrapperBlockStateModel(BlockStateModel wrapped) { } @Override - public void collectParts(RandomSource random, List parts) { + public void collectParts(RandomSource random, List parts) { wrapped.collectParts(random, parts); } @Override - public List collectParts(RandomSource random) { - return wrapped.collectParts(random); + public Material.Baked particleMaterial() { + return wrapped.particleMaterial(); } @Override - public TextureAtlasSprite particleIcon() { - return wrapped.particleIcon(); + public @BakedQuad.MaterialFlags int materialFlags() { + return wrapped.materialFlags(); + } + + @Override + public boolean hasMaterialFlag(@BakedQuad.MaterialFlags int flag) { + return wrapped.hasMaterialFlag(flag); } @Override @@ -73,7 +79,7 @@ public Object createGeometryKey(BlockAndTintGetter level, BlockPos pos, BlockSta } @Override - public TextureAtlasSprite particleIcon(BlockAndTintGetter level, BlockPos pos, BlockState state) { - return wrapped.particleIcon(level, pos, state); + public Material.Baked particleMaterial(BlockAndTintGetter level, BlockPos pos, BlockState state) { + return wrapped.particleMaterial(level, pos, state); } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/wrapper/WrapperUnbakedItemModel.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/wrapper/WrapperUnbakedItemModel.java index b0ff939fe81..a304d990d58 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/wrapper/WrapperUnbakedItemModel.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/wrapper/WrapperUnbakedItemModel.java @@ -17,6 +17,7 @@ package net.fabricmc.fabric.api.client.model.loading.v1.wrapper; import com.mojang.serialization.MapCodec; +import org.joml.Matrix4fc; import net.minecraft.client.renderer.item.ItemModel; @@ -45,7 +46,7 @@ public MapCodec type() { } @Override - public ItemModel bake(ItemModel.BakingContext context) { - return wrapped.bake(context); + public ItemModel bake(ItemModel.BakingContext context, Matrix4fc transformation) { + return wrapped.bake(context, transformation); } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/wrapper/WrapperUnbakedModel.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/wrapper/WrapperUnbakedModel.java index 6642225fdc1..8d52e6b81a6 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/wrapper/WrapperUnbakedModel.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/wrapper/WrapperUnbakedModel.java @@ -18,10 +18,10 @@ import org.jspecify.annotations.Nullable; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.renderer.block.model.TextureSlots; -import net.minecraft.client.resources.model.UnbakedGeometry; import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.client.resources.model.cuboid.ItemTransforms; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.resources.model.sprite.TextureSlots; import net.minecraft.resources.Identifier; /** diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/wrapper/WrapperUnbakedRootBlockStateModel.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/wrapper/WrapperUnbakedRootBlockStateModel.java index f6c192325e9..e4a48505055 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/wrapper/WrapperUnbakedRootBlockStateModel.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/api/client/model/loading/v1/wrapper/WrapperUnbakedRootBlockStateModel.java @@ -16,7 +16,7 @@ package net.fabricmc.fabric.api.client.model.loading.v1.wrapper; -import net.minecraft.client.renderer.block.model.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; import net.minecraft.client.resources.model.ModelBaker; import net.minecraft.world.level.block.state.BlockState; diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/CompositeBlockStateModelImpl.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/CompositeBlockStateModelImpl.java index de344a2e40f..4379fdf5d2b 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/CompositeBlockStateModelImpl.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/CompositeBlockStateModelImpl.java @@ -28,15 +28,16 @@ import org.jetbrains.annotations.UnmodifiableView; import org.jspecify.annotations.Nullable; -import net.minecraft.client.renderer.block.model.BlockModelPart; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; +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.resources.model.ModelBaker; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.ExtraCodecs; import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; import net.fabricmc.fabric.api.client.model.loading.v1.CompositeBlockStateModel; @@ -46,10 +47,19 @@ public class CompositeBlockStateModelImpl implements CompositeBlockStateModel { private final BlockStateModel[] models; @UnmodifiableView private final List modelsView; + private final @BakedQuad.MaterialFlags int materialFlags; public CompositeBlockStateModelImpl(BlockStateModel[] models) { this.models = models; modelsView = Arrays.asList(models); + + @BakedQuad.MaterialFlags int materialFlags = 0; + + for (BlockStateModel model : this.models) { + materialFlags |= model.materialFlags(); + } + + this.materialFlags = materialFlags; } public static CompositeBlockStateModelImpl of(List models) { @@ -68,7 +78,7 @@ public List models() { } @Override - public void collectParts(RandomSource random, List parts) { + public void collectParts(RandomSource random, List parts) { long seed = random.nextLong(); for (BlockStateModel model : models) { @@ -118,13 +128,18 @@ record Key(List subkeys) { } @Override - public TextureAtlasSprite particleIcon() { - return models[0].particleIcon(); + public Material.Baked particleMaterial() { + return models[0].particleMaterial(); + } + + @Override + public Material.Baked particleMaterial(BlockAndTintGetter level, BlockPos pos, BlockState state) { + return models[0].particleMaterial(level, pos, state); } @Override - public TextureAtlasSprite particleIcon(BlockAndTintGetter level, BlockPos pos, BlockState state) { - return models[0].particleIcon(level, pos, state); + public @BakedQuad.MaterialFlags int materialFlags() { + return materialFlags; } public record Unbaked(@Unmodifiable List models) implements CompositeBlockStateModel.Unbaked { diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/CustomUnbakedBlockStateModelRegistry.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/CustomUnbakedBlockStateModelRegistry.java index 9b61409e1da..843435b528a 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/CustomUnbakedBlockStateModelRegistry.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/CustomUnbakedBlockStateModelRegistry.java @@ -32,10 +32,10 @@ import com.mojang.serialization.RecordBuilder; import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.block.model.SingleVariant; -import net.minecraft.client.renderer.block.model.Variant; -import net.minecraft.client.resources.model.WeightedVariants; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.SingleVariant; +import net.minecraft.client.renderer.block.dispatch.Variant; +import net.minecraft.client.renderer.block.dispatch.WeightedVariants; import net.minecraft.resources.Identifier; import net.minecraft.util.ExtraCodecs; import net.minecraft.util.random.Weighted; @@ -63,7 +63,7 @@ public class CustomUnbakedBlockStateModelRegistry { ExtraCodecs.POSITIVE_INT.optionalFieldOf("weight", 1).forGetter(Weighted::weight) ).apply(instance, Weighted::new) ); - /** Extended codec for a vanilla weighted model that supports using custom models instead of regular variants. Replaces {@link BlockStateModel.Unbaked#WEIGHTED_CODEC}. */ + /** Extended codec for a vanilla weighted model that supports using custom models instead of regular variants. Replaces {@link BlockStateModel.Unbaked#HARDCODED_WEIGHTED_CODEC}. */ public static final Codec WEIGHTED_MODEL_CODEC = ExtraCodecs.nonEmptyList(WEIGHTED_VARIANT_CODEC.listOf()) .flatComapMap( weightedVariants -> new WeightedVariants.Unbaked(WeightedList.of(Lists.transform(weightedVariants, weighted -> weighted.map(either -> either.map(Function.identity(), Function.identity()))))), diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingEventDispatcher.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingEventDispatcher.java index c0ee1ff147e..3fabdd52272 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingEventDispatcher.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/ModelLoadingEventDispatcher.java @@ -26,11 +26,12 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; +import org.joml.Matrix4fc; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import net.minecraft.client.renderer.block.model.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; import net.minecraft.client.renderer.item.ItemModel; import net.minecraft.client.resources.model.BlockStateModelLoader; import net.minecraft.client.resources.model.ModelBaker; @@ -154,10 +155,10 @@ public BlockStateModel modifyBlockModel(BlockStateModel.UnbakedRoot unbakedModel return pluginContext.modifyBlockModelAfterBake().invoker().modifyModelAfterBake(model, modifierContext); } - public ItemModel modifyItemModel(ItemModel.Unbaked unbakedModel, Identifier itemId, ItemModel.BakingContext bakeContext, Operation bakeOperation) { - BakeItemModifierContext modifierContext = new BakeItemModifierContext(itemId, bakeContext); + public ItemModel modifyItemModel(ItemModel.Unbaked unbakedModel, Identifier itemId, ItemModel.BakingContext bakeContext, Matrix4fc transformation, Operation bakeOperation) { + BakeItemModifierContext modifierContext = new BakeItemModifierContext(itemId, bakeContext, transformation); unbakedModel = pluginContext.modifyItemModelBeforeBake().invoker().modifyModelBeforeBake(unbakedModel, modifierContext); - ItemModel model = bakeOperation.call(unbakedModel, bakeContext); + ItemModel model = bakeOperation.call(unbakedModel, bakeContext, transformation); modifierContext.prepareAfterBake(unbakedModel); return pluginContext.modifyItemModelAfterBake().invoker().modifyModelAfterBake(model, modifierContext); } @@ -250,11 +251,13 @@ public BlockStateModel.UnbakedRoot sourceModel() { private static class BakeItemModifierContext implements ModelModifier.BeforeBakeItem.Context, ModelModifier.AfterBakeItem.Context { private final Identifier itemId; private final ItemModel.BakingContext bakeContext; + private final Matrix4fc transformation; private ItemModel.Unbaked sourceModel; - private BakeItemModifierContext(Identifier itemId, ItemModel.BakingContext bakeContext) { + private BakeItemModifierContext(Identifier itemId, ItemModel.BakingContext bakeContext, Matrix4fc transformation) { this.itemId = itemId; this.bakeContext = bakeContext; + this.transformation = transformation; } private void prepareAfterBake(ItemModel.Unbaked sourceModel) { @@ -271,6 +274,11 @@ public ItemModel.BakingContext bakingContext() { return bakeContext; } + @Override + public Matrix4fc transformation() { + return transformation; + } + @Override public ItemModel.Unbaked sourceModel() { return sourceModel; diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/UnbakedModelDeserializerRegistry.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/UnbakedModelDeserializerRegistry.java index c78ac064dab..0bafb28d25e 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/UnbakedModelDeserializerRegistry.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/UnbakedModelDeserializerRegistry.java @@ -28,7 +28,7 @@ import net.minecraft.util.GsonHelper; import net.fabricmc.fabric.api.client.model.loading.v1.UnbakedModelDeserializer; -import net.fabricmc.fabric.mixin.client.model.loading.BlockModelAccessor; +import net.fabricmc.fabric.mixin.client.model.loading.CuboidModelAccessor; public class UnbakedModelDeserializerRegistry { private static final Map DESERIALIZERS = new HashMap<>(); @@ -49,6 +49,6 @@ public static UnbakedModelDeserializer get(Identifier id) { } public static UnbakedModel deserialize(Reader reader) throws JsonParseException { - return GsonHelper.fromJson(BlockModelAccessor.fabric_getGson(), reader, UnbakedModel.class); + return GsonHelper.fromJson(CuboidModelAccessor.fabric_getGson(), reader, UnbakedModel.class); } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/UnbakedModelJsonDeserializer.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/UnbakedModelJsonDeserializer.java index f3726aee08e..5aeb2512ffe 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/UnbakedModelJsonDeserializer.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/impl/client/model/loading/UnbakedModelJsonDeserializer.java @@ -25,8 +25,8 @@ import com.google.gson.JsonParseException; import com.google.gson.JsonSyntaxException; -import net.minecraft.client.renderer.block.model.BlockModel; import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.client.resources.model.cuboid.CuboidModel; import net.minecraft.resources.Identifier; import net.minecraft.util.GsonHelper; @@ -67,6 +67,6 @@ public UnbakedModel deserialize(JsonElement jsonElement, Type typeOfT, JsonDeser } } - return context.deserialize(jsonElement, BlockModel.class); + return context.deserialize(jsonElement, CuboidModel.class); } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BlockStateModelUnbakedMixin.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BlockStateModelUnbakedMixin.java index 50f4779d1ef..2438911e2b9 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BlockStateModelUnbakedMixin.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BlockStateModelUnbakedMixin.java @@ -25,10 +25,10 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.block.model.SingleVariant; -import net.minecraft.client.renderer.block.model.Variant; -import net.minecraft.client.resources.model.WeightedVariants; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.SingleVariant; +import net.minecraft.client.renderer.block.dispatch.Variant; +import net.minecraft.client.renderer.block.dispatch.WeightedVariants; import net.minecraft.util.random.Weighted; import net.fabricmc.fabric.impl.client.model.loading.CustomUnbakedBlockStateModelRegistry; diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BlockModelAccessor.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/CuboidModelAccessor.java similarity index 87% rename from fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BlockModelAccessor.java rename to fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/CuboidModelAccessor.java index e90a8e25f21..3af9b81bd3c 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BlockModelAccessor.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/CuboidModelAccessor.java @@ -20,10 +20,10 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.client.resources.model.cuboid.CuboidModel; -@Mixin(BlockModel.class) -public interface BlockModelAccessor { +@Mixin(CuboidModel.class) +public interface CuboidModelAccessor { @Accessor("GSON") static Gson fabric_getGson() { throw new AssertionError(); diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BlockModelMixin.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/CuboidModelMixin.java similarity index 91% rename from fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BlockModelMixin.java rename to fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/CuboidModelMixin.java index e0ee132a50c..933f3e752b8 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/BlockModelMixin.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/CuboidModelMixin.java @@ -21,13 +21,13 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import net.minecraft.client.renderer.block.model.BlockModel; import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.client.resources.model.cuboid.CuboidModel; import net.fabricmc.fabric.impl.client.model.loading.UnbakedModelJsonDeserializer; -@Mixin(BlockModel.class) -abstract class BlockModelMixin { +@Mixin(CuboidModel.class) +abstract class CuboidModelMixin { @ModifyExpressionValue(method = "()V", at = @At(value = "NEW", target = "com/google/gson/GsonBuilder")) private static GsonBuilder addUnbakedModelAdapter(GsonBuilder builder) { return builder.registerTypeHierarchyAdapter(UnbakedModel.class, new UnbakedModelJsonDeserializer()); diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelBakeryMixin.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelBakeryMixin.java index 7f37a6c2da1..00ecc1aa657 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelBakeryMixin.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelBakeryMixin.java @@ -25,6 +25,7 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; +import org.joml.Matrix4fc; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.spongepowered.asm.mixin.Final; @@ -36,7 +37,7 @@ import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import net.minecraft.client.renderer.block.model.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; import net.minecraft.client.renderer.item.ItemModel; import net.minecraft.client.resources.model.ModelBaker; import net.minecraft.client.resources.model.ModelBakery; @@ -100,7 +101,7 @@ private CompletableFuture withExtraModels(CompletableF }); } - @WrapOperation(method = "lambda$bakeModels$0", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/block/model/BlockStateModel$UnbakedRoot;bake(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/client/resources/model/ModelBaker;)Lnet/minecraft/client/renderer/block/model/BlockStateModel;")) + @WrapOperation(method = "lambda$bakeModels$0", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/block/dispatch/BlockStateModel$UnbakedRoot;bake(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/client/resources/model/ModelBaker;)Lnet/minecraft/client/renderer/block/dispatch/BlockStateModel;")) private static BlockStateModel wrapBlockModelBake(BlockStateModel.UnbakedRoot unbakedModel, BlockState state, ModelBaker baker, Operation operation) { ModelLoadingEventDispatcher eventDispatcher = ModelLoadingEventDispatcher.CURRENT.get(); @@ -111,12 +112,12 @@ private static BlockStateModel wrapBlockModelBake(BlockStateModel.UnbakedRoot un return eventDispatcher.modifyBlockModel(unbakedModel, state, baker, operation); } - @WrapOperation(method = "lambda$bakeModels$1", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/item/ItemModel$Unbaked;bake(Lnet/minecraft/client/renderer/item/ItemModel$BakingContext;)Lnet/minecraft/client/renderer/item/ItemModel;")) - private ItemModel wrapItemModelBake(ItemModel.Unbaked unbakedModel, ItemModel.BakingContext bakeContext, Operation operation, @Local(argsOnly = true) Identifier itemId) { + @WrapOperation(method = "lambda$bakeModels$1", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/item/ItemModel$Unbaked;bake(Lnet/minecraft/client/renderer/item/ItemModel$BakingContext;Lorg/joml/Matrix4fc;)Lnet/minecraft/client/renderer/item/ItemModel;")) + private ItemModel wrapItemModelBake(ItemModel.Unbaked unbakedModel, ItemModel.BakingContext bakeContext, Matrix4fc transformation, Operation operation, @Local(argsOnly = true) Identifier itemId) { if (fabric_eventDispatcher == null) { - return operation.call(unbakedModel, bakeContext); + return operation.call(unbakedModel, bakeContext, transformation); } - return fabric_eventDispatcher.modifyItemModel(unbakedModel, itemId, bakeContext, operation); + return fabric_eventDispatcher.modifyItemModel(unbakedModel, itemId, bakeContext, transformation, operation); } } diff --git a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelManagerMixin.java b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelManagerMixin.java index 193a2bc7b5c..d7837453f44 100644 --- a/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelManagerMixin.java +++ b/fabric-model-loading-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/model/loading/ModelManagerMixin.java @@ -35,13 +35,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import net.minecraft.client.renderer.block.model.BlockModel; import net.minecraft.client.resources.model.BlockStateModelLoader; import net.minecraft.client.resources.model.ClientItemInfoLoader; import net.minecraft.client.resources.model.ModelBakery; import net.minecraft.client.resources.model.ModelDiscovery; import net.minecraft.client.resources.model.ModelManager; import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.client.resources.model.cuboid.CuboidModel; import net.minecraft.resources.Identifier; import net.minecraft.server.packs.resources.PreparableReloadListener; @@ -134,8 +134,8 @@ private void onReturnUpload(CallbackInfo ci, @Local(name = "bakedModels") ModelB // We want to redirect the BlockModel.deserialize call, but its return type is BlockModel, so we can't // do that directly. // Instead, cancel the original call and then modify the null value when it's being used to construct the Pair. - @Redirect(method = "lambda$loadBlockModels$2(Ljava/util/Map$Entry;)Lcom/mojang/datafixers/util/Pair;", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/block/model/BlockModel;fromStream(Ljava/io/Reader;)Lnet/minecraft/client/renderer/block/model/BlockModel;")) - private static BlockModel cancelVanillaDeserialize(Reader reader) { + @Redirect(method = "lambda$loadBlockModels$2(Ljava/util/Map$Entry;)Lcom/mojang/datafixers/util/Pair;", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/cuboid/CuboidModel;fromStream(Ljava/io/Reader;)Lnet/minecraft/client/resources/model/cuboid/CuboidModel;")) + private static CuboidModel cancelVanillaDeserialize(Reader reader) { return null; } diff --git a/fabric-model-loading-api-v1/src/client/resources/fabric-model-loading-api-v1.mixins.json b/fabric-model-loading-api-v1/src/client/resources/fabric-model-loading-api-v1.mixins.json index 3d2eb4b7763..a17743e086c 100644 --- a/fabric-model-loading-api-v1/src/client/resources/fabric-model-loading-api-v1.mixins.json +++ b/fabric-model-loading-api-v1/src/client/resources/fabric-model-loading-api-v1.mixins.json @@ -4,8 +4,8 @@ "compatibilityLevel": "JAVA_25", "client": [ "ModelManagerMixin", - "BlockModelAccessor", - "BlockModelMixin", + "CuboidModelAccessor", + "CuboidModelMixin", "ModelBakeryBakingResultMixin", "ModelBakeryMixin", "BlockStateModelUnbakedMixin" diff --git a/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/BakedModelRenderLayer.java b/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/BakedModelRenderLayer.java index 4f92befbd5f..dcfcebc837a 100644 --- a/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/BakedModelRenderLayer.java +++ b/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/BakedModelRenderLayer.java @@ -20,19 +20,31 @@ import com.mojang.blaze3d.vertex.PoseStack; import org.joml.AxisAngle4f; +import org.joml.Matrix4f; +import org.joml.Matrix4fc; import org.joml.Quaternionf; import net.minecraft.client.model.EntityModel; -import net.minecraft.client.renderer.Sheets; import net.minecraft.client.renderer.SubmitNodeCollector; -import net.minecraft.client.renderer.block.model.BlockStateModel; +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.BlockModelRenderState; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; +import net.minecraft.client.renderer.block.model.BlockDisplayContext; import net.minecraft.client.renderer.entity.RenderLayerParent; import net.minecraft.client.renderer.entity.layers.RenderLayer; import net.minecraft.client.renderer.entity.state.LivingEntityRenderState; import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.core.BlockPos; import net.minecraft.util.Mth; +import net.minecraft.world.level.block.Blocks; + +import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter; public class BakedModelRenderLayer> extends RenderLayer { + private static final Matrix4fc IDENTITY_MATRIX4FC = new Matrix4f(); + public static final BlockDisplayContext BLOCK_DISPLAY_CONTEXT = BlockDisplayContext.create(); + private final Supplier modelSupplier; public BakedModelRenderLayer(RenderLayerParent context, Supplier modelSupplier) { @@ -48,9 +60,22 @@ public void submit(PoseStack poseStack, SubmitNodeCollector nodeCollector, int l poseStack.scale(-0.75F, -0.75F, 0.75F); float aboveHead = (float) (Math.sin(state.ageInTicks * 0.08F)) * 0.5F + 0.5F; poseStack.translate(-0.5F, 0.75F + aboveHead, -0.5F); - // FIXME 1.21.9 - // FabricBlockModelRenderer.render(matrices.peek(), RenderLayerHelper.entityDelegate(bufferSource), model, 1, 1, 1, light, OverlayTexture.DEFAULT_UV, EmptyBlockRenderView.INSTANCE, BlockPos.ORIGIN, Blocks.AIR.getDefaultState()); - nodeCollector.order(0).submitBlockModel(poseStack, Sheets.cutoutBlockSheet(), model, 1, 1, 1, light, OverlayTexture.NO_OVERLAY, 0); + + // Normally the BlockModelRenderState would be stored in the entity render state and it + // would be populated in the entity renderer's extractRenderState method, but that doesn't + // seem possible to do without mixins for this case + BlockModelRenderState renderState = new BlockModelRenderState(); + QuadEmitter emitter = renderState.setupMesh(IDENTITY_MATRIX4FC, model.hasMaterialFlag(BakedQuad.FLAG_TRANSLUCENT)); + model.emitQuads( + emitter, + BlockAndTintGetter.EMPTY, + BlockPos.ZERO, + Blocks.AIR.defaultBlockState(), + renderState.scratchRandomSource(42L), + _ -> false + ); + renderState.submit(poseStack, nodeCollector, light, OverlayTexture.NO_OVERLAY, 0); + poseStack.popPose(); } } diff --git a/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/ModelTestModClient.java b/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/ModelTestModClient.java index 11b98164f03..1a2dcf66d4b 100644 --- a/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/ModelTestModClient.java +++ b/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/ModelTestModClient.java @@ -20,17 +20,17 @@ import org.jspecify.annotations.Nullable; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.block.model.SingleVariant; -import net.minecraft.client.renderer.block.model.Variant; +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.SingleVariant; +import net.minecraft.client.renderer.block.dispatch.Variant; import net.minecraft.client.renderer.entity.player.AvatarRenderer; -import net.minecraft.client.resources.model.MissingBlockModel; +import net.minecraft.client.resources.model.cuboid.MissingCuboidModel; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.resources.Identifier; import net.minecraft.server.packs.PackType; import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.CropBlock; import net.minecraft.world.level.block.CrossCollisionBlock; @@ -101,7 +101,7 @@ public void onInitializeClient() { BlockState westOakFence = Blocks.OAK_FENCE.defaultBlockState().setValue(CrossCollisionBlock.WEST, true); pluginContext.modifyBlockModelOnLoad().register(ModelModifier.OVERRIDE_PHASE, (model, context) -> { if (context.state() == westOakFence) { - return simpleUnbakedGroupedBlockStateModel(MissingBlockModel.LOCATION); + return simpleUnbakedGroupedBlockStateModel(MissingCuboidModel.LOCATION); } return model; diff --git a/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/PreparablePluginTest.java b/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/PreparablePluginTest.java index f6e77d4a3a3..a8536762453 100644 --- a/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/PreparablePluginTest.java +++ b/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/PreparablePluginTest.java @@ -29,10 +29,10 @@ import org.jspecify.annotations.Nullable; import org.slf4j.Logger; -import net.minecraft.client.renderer.block.model.BlockModel; -import net.minecraft.client.resources.model.AtlasManager; import net.minecraft.client.resources.model.ModelManager; import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.client.resources.model.cuboid.CuboidModel; +import net.minecraft.client.resources.model.sprite.AtlasManager; import net.minecraft.resources.FileToIdConverter; import net.minecraft.resources.Identifier; import net.minecraft.server.packs.resources.PreparableReloadListener; @@ -71,11 +71,11 @@ public void onInitializeClient() { /** * Adaptation of the {@link ModelManager} method. */ - private static CompletableFuture> loadModelReplacements(PreparableReloadListener.SharedState resourceReloaderStore, Executor executor) { + private static CompletableFuture> loadModelReplacements(PreparableReloadListener.SharedState resourceReloaderStore, Executor executor) { Objects.requireNonNull(resourceReloaderStore.get(AtlasManager.PENDING_STITCH)); return CompletableFuture.supplyAsync(() -> MODEL_REPLACEMENTS_FINDER.listMatchingResources(resourceReloaderStore.resourceManager()), executor).thenCompose(models2 -> { - ArrayList>> list = new ArrayList<>(models2.size()); + ArrayList>> list = new ArrayList<>(models2.size()); for (Map.Entry entry : models2.entrySet()) { list.add(CompletableFuture.supplyAsync(() -> { @@ -83,7 +83,7 @@ private static CompletableFuture> loadModelReplaceme // Remove model_replacements/ prefix from the identifier Identifier modelId = MODEL_REPLACEMENTS_FINDER.fileToId(entry.getKey()); - return Pair.of(modelId, BlockModel.fromStream(reader)); + return Pair.of(modelId, CuboidModel.fromStream(reader)); } catch (Exception exception) { LOGGER.error("Failed to load model {}", entry.getKey(), exception); return null; diff --git a/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/SpecificModelReloadListener.java b/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/SpecificModelReloadListener.java index 4a2cf0cf409..0ef8fff1652 100644 --- a/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/SpecificModelReloadListener.java +++ b/fabric-model-loading-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/model/loading/SpecificModelReloadListener.java @@ -17,7 +17,7 @@ package net.fabricmc.fabric.test.model.loading; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.model.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; import net.minecraft.resources.Identifier; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.ResourceManagerReloadListener; 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 9d0160323ec..31b28329664 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 @@ -17,33 +17,23 @@ package net.fabricmc.fabric.api.client.renderer.v1; import java.util.List; -import java.util.function.Predicate; +import java.util.function.Consumer; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import org.jetbrains.annotations.ApiStatus; -import org.jspecify.annotations.Nullable; - -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.block.BlockRenderDispatcher; +import net.minecraft.client.color.block.BlockColors; +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.model.BlockStateModel; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; import net.minecraft.client.renderer.chunk.SectionCompiler; -import net.minecraft.client.renderer.item.ItemStackRenderState; import net.minecraft.core.BlockPos; import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; import net.fabricmc.api.ModInitializer; 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.BlockMultiBufferSource; -import net.fabricmc.fabric.api.client.renderer.v1.render.FabricBlockRenderDispatcher; -import net.fabricmc.fabric.api.client.renderer.v1.render.FabricLayerRenderState; -import net.fabricmc.fabric.api.client.renderer.v1.render.FabricModelBlockRenderer; -import net.fabricmc.fabric.api.client.renderer.v1.render.ItemRenderTypeGetter; +import net.fabricmc.fabric.api.client.renderer.v1.render.AltModelBlockRenderer; import net.fabricmc.fabric.impl.client.renderer.RendererManager; /** @@ -51,21 +41,15 @@ * for model lighting, buffering and rendering. Such plug-ins implement the * enhanced model rendering interfaces specified by the Fabric API. * - *

Renderers must ensure that terrain buffering supports {@link BlockStateModel#emitQuads}, which happens in - * {@link SectionCompiler} in vanilla; this code is not patched automatically. Renderers must also ensure that the - * following vanilla methods support {@link BlockStateModel#emitQuads}; these methods are not patched automatically. - * - *

  • {@link ModelBlockRenderer#renderModel(PoseStack.Pose, VertexConsumer, BlockStateModel, float, float, float, int, int)} - * - *
  • {@link BlockRenderDispatcher#renderBreakingTexture(BlockState, BlockPos, BlockAndTintGetter, PoseStack, VertexConsumer)} + *

    Renderers must ensure that terrain buffering supports {@link BlockStateModel#emitQuads}, if they introduce an + * alternate path for it. In vanilla, this happens in {@link SectionCompiler}, which is automatically patched to use + * {@link #altModelBlockRenderer(boolean, boolean, BlockColors)}. * - *

  • {@link BlockRenderDispatcher#renderSingleBlock(BlockState, PoseStack, MultiBufferSource, int, int)}
- * - *

All other places in vanilla code that invoke {@link BlockStateModel#collectParts(RandomSource, List)}, - * {@link BlockStateModel#collectParts(RandomSource)}, or - * {@link ModelBlockRenderer#renderModel(PoseStack.Pose, VertexConsumer, BlockStateModel, float, float, float, int, int)} - * are, where appropriate, patched automatically to invoke the corresponding method above or the corresponding method in - * {@link FabricModelBlockRenderer} or {@link FabricBlockRenderDispatcher}. + *

All places in vanilla code that invoke {@link BlockStateModel#collectParts(RandomSource, List)} or + * {@link ModelBlockRenderer#tesselateBlock(BlockQuadOutput, float, float, float, BlockAndTintGetter, BlockPos, BlockState, BlockStateModel, long)} + * are, where appropriate, patched automatically to invoke {@link BlockStateModel#emitQuads} or + * {@link AltModelBlockRenderer#tesselateBlock(QuadEmitter, float, float, float, BlockAndTintGetter, BlockPos, BlockState, BlockStateModel, long)}, + * respectively, instead. */ public interface Renderer { /** @@ -80,6 +64,14 @@ static Renderer get() { return RendererManager.getRenderer(); } + /** + * Obtain a new {@link QuadEmitter} instance that invokes the given consumer on + * {@link QuadEmitter#emit()}, after transforms are applied. + * + * @param consumer logic performed when the quad is emitted. + */ + QuadEmitter quadEmitter(Consumer consumer); + /** * Obtain a new {@link MutableMesh} instance to build optimized meshes and create baked models * with enhanced features. @@ -90,32 +82,9 @@ static Renderer get() { MutableMesh mutableMesh(); /** - * @see FabricModelBlockRenderer#tesselateBlock(BlockAndTintGetter, BlockStateModel, BlockState, BlockPos, PoseStack, BlockMultiBufferSource, Predicate, boolean, long, int) - */ - @ApiStatus.OverrideOnly - void tesselateBlock(ModelBlockRenderer blockRenderer, BlockAndTintGetter level, BlockStateModel model, BlockState state, BlockPos pos, PoseStack poseStack, BlockMultiBufferSource bufferSource, @Nullable Predicate layerFilter, boolean cull, long seed, int overlay); - - /** - * @see FabricModelBlockRenderer#renderModel(PoseStack.Pose, BlockMultiBufferSource, Predicate, BlockStateModel, float, float, float, int, int, BlockAndTintGetter, BlockPos, BlockState) - */ - @ApiStatus.OverrideOnly - void renderModel(PoseStack.Pose pose, BlockMultiBufferSource bufferSource, @Nullable Predicate layerFilter, BlockStateModel model, float red, float green, float blue, int light, int overlay, BlockAndTintGetter level, BlockPos pos, BlockState state); - - /** - * @see FabricBlockRenderDispatcher#renderSingleBlock(BlockState, PoseStack, MultiBufferSource, Predicate, int, int, BlockAndTintGetter, BlockPos) - */ - @ApiStatus.OverrideOnly - void renderSingleBlock(BlockRenderDispatcher renderDispatcher, BlockState state, PoseStack poseStack, MultiBufferSource bufferSource, @Nullable Predicate layerFilter, int light, int overlay, BlockAndTintGetter level, BlockPos pos); - - /** - * @see FabricLayerRenderState#emitter() - */ - @ApiStatus.OverrideOnly - QuadEmitter getLayerRenderStateEmitter(ItemStackRenderState.LayerRenderState layer); - - /** - * @see FabricLayerRenderState#setRenderTypeGetter(ItemRenderTypeGetter) + * Obtain a new {@link AltModelBlockRenderer} instance to tesselate blocks with + * {@linkplain QuadEmitter modded quads}. Prefer using this over the vanilla + * {@link ModelBlockRenderer} to correctly tesselate modded models. */ - @ApiStatus.OverrideOnly - void setLayerRenderTypeGetter(ItemStackRenderState.LayerRenderState layer, ItemRenderTypeGetter renderTypeGetter); + AltModelBlockRenderer altModelBlockRenderer(boolean ambientOcclusion, boolean cull, BlockColors blockColors); } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/mesh/MutableQuadView.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/mesh/MutableQuadView.java index 78573cd2fdb..e393f995e15 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/mesh/MutableQuadView.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/mesh/MutableQuadView.java @@ -22,18 +22,22 @@ import org.joml.Vector3fc; import org.jspecify.annotations.Nullable; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.ItemBlockRenderTypes; -import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.Sheets; import net.minecraft.client.renderer.chunk.ChunkSectionLayer; import net.minecraft.client.renderer.item.ItemStackRenderState; import net.minecraft.client.renderer.rendertype.RenderType; +import net.minecraft.client.renderer.state.OptionsRenderState; import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.Direction; +import net.minecraft.util.ARGB; +import net.minecraft.util.LightCoordsUtil; import net.minecraft.world.level.block.state.BlockState; -import net.fabricmc.fabric.api.client.renderer.v1.render.FabricLayerRenderState; -import net.fabricmc.fabric.api.client.renderer.v1.render.ItemRenderTypeGetter; +import net.fabricmc.fabric.api.client.renderer.v1.model.ModelHelper; +import net.fabricmc.fabric.api.client.renderer.v1.render.ExtraLightCoordsUtil; +import net.fabricmc.fabric.api.client.renderer.v1.sprite.SpriteFinder; import net.fabricmc.fabric.api.util.TriState; import net.fabricmc.fabric.impl.client.renderer.QuadSpriteBaker; @@ -54,25 +58,25 @@ public interface MutableQuadView extends QuadView { /** * When enabled, causes texture to appear with no rotation. This is the default and does not have to be specified * explicitly. Can be overridden by other rotation flags. - * Pass in bakeFlags parameter to {@link #spriteBake(TextureAtlasSprite, int)}. + * Pass in bakeFlags parameter to {@link #materialBake(Material.Baked, int)}. */ int BAKE_ROTATE_NONE = 0; /** * When enabled, causes texture to appear rotated 90 degrees clockwise. - * Pass in bakeFlags parameter to {@link #spriteBake(TextureAtlasSprite, int)}. + * Pass in bakeFlags parameter to {@link #materialBake(Material.Baked, int)}. */ int BAKE_ROTATE_90 = 1; /** * When enabled, causes texture to appear rotated 180 degrees. - * Pass in bakeFlags parameter to {@link #spriteBake(TextureAtlasSprite, int)}. + * Pass in bakeFlags parameter to {@link #materialBake(Material.Baked, int)}. */ int BAKE_ROTATE_180 = 2; /** * When enabled, causes texture to appear rotated 270 degrees clockwise. - * Pass in bakeFlags parameter to {@link #spriteBake(TextureAtlasSprite, int)}. + * Pass in bakeFlags parameter to {@link #materialBake(Material.Baked, int)}. */ int BAKE_ROTATE_270 = 3; @@ -80,7 +84,7 @@ public interface MutableQuadView extends QuadView { * When enabled, texture coordinates are assigned based on vertex positions and the * {@linkplain #nominalFace() nominal face}. * Any existing UV coordinates will be replaced and the {@link #BAKE_NORMALIZED} flag will be ignored. - * Pass in bakeFlags parameter to {@link #spriteBake(TextureAtlasSprite, int)}. + * Pass in bakeFlags parameter to {@link #materialBake(Material.Baked, int)}. * *

UV lock derives texture coordinates based on {@linkplain #nominalFace() nominal face} by projecting the quad * onto it, even when the quad is not co-planar with it. This flag is ignored if the normal face is {@code null}. @@ -93,7 +97,7 @@ public interface MutableQuadView extends QuadView { * and texture mapping scenarios. Results are different from what * can be obtained via rotation and both can be applied. Any * rotation is applied before this flag. - * Pass in bakeFlags parameter to {@link #spriteBake(TextureAtlasSprite, int)}. + * Pass in bakeFlags parameter to {@link #materialBake(Material.Baked, int)}. */ int BAKE_FLIP_U = 8; @@ -107,7 +111,7 @@ public interface MutableQuadView extends QuadView { * with conventional Minecraft model format. This is scaled to 0-1 during * baking before interpolation. Model loaders that already have 0-1 coordinates * can avoid wasteful multiplication/division by passing 0-1 coordinates directly. - * Pass in bakeFlags parameter to {@link #spriteBake(TextureAtlasSprite, int)}. + * Pass in bakeFlags parameter to {@link #materialBake(Material.Baked, int)}. */ int BAKE_NORMALIZED = 32; @@ -138,6 +142,17 @@ default MutableQuadView pos(int vertexIndex, Vector3fc pos) { return pos(vertexIndex, pos.x(), pos.y(), pos.z()); } + /** + * Translates the geometric positions of all vertices of this quad by the given offset. + */ + default MutableQuadView translate(float x, float y, float z) { + pos(0, x(0) + x, y(0) + y, z(0) + z); + pos(1, x(1) + x, y(1) + y, z(1) + z); + pos(2, x(2) + x, y(2) + y, z(2) + z); + pos(3, x(3) + x, y(3) + y, z(3) + z); + return this; + } + /** * Sets the color in ARGB format (0xAARRGGBB) for the given vertex. * @@ -158,6 +173,20 @@ default MutableQuadView color(int c0, int c1, int c2, int c3) { return this; } + /** + * Multiplies all components of each of this quad's vertex colors by the given color in ARGB + * format (0xAARRGGBB). + * + * @param color the color in ARGB format (0xAARRGGBB) to multiply by + */ + default MutableQuadView multiplyColor(int color) { + color(0, ARGB.multiply(color(0), color)); + color(1, ARGB.multiply(color(1), color)); + color(2, ARGB.multiply(color(2), color)); + color(3, ARGB.multiply(color(3), color)); + return this; + } + /** * Sets the texture coordinates for the given vertex. * @@ -181,20 +210,45 @@ default MutableQuadView uv(int vertexIndex, Vector2fc uv) { return uv(vertexIndex, uv.x(), uv.y()); } + default MutableQuadView uvUnitSquare() { + uv(0, 0, 0); + uv(1, 0, 1); + uv(2, 1, 1); + uv(3, 1, 0); + return this; + } + /** - * Sets the texture coordinates for all vertices using the given sprite. Also sets this quad's atlas to the given - * sprite's atlas. Can handle UV locking, rotation, interpolation, etc. Control this behavior by passing additive - * combinations of the BAKE_ flags defined in this interface. + * Sets the texture coordinates for all vertices using the given material's sprite. Also sets this quad's + * {@linkplain #atlas(QuadAtlas) atlas}, {@linkplain #chunkLayer(ChunkSectionLayer) chunk layer}, + * {@linkplain #animated(boolean)}, and {@linkplain #itemRenderType(RenderType) item render type} + * to appropriate values based on the given material. Can handle UV locking, rotation, + * interpolation, etc. Control this behavior by passing additive combinations of the BAKE_ flags + * defined in this interface. */ - default MutableQuadView spriteBake(TextureAtlasSprite sprite, int bakeFlags) { - QuadSpriteBaker.bakeSprite(this, sprite, bakeFlags); - QuadAtlas atlas = QuadAtlas.of(sprite.atlasLocation()); + default MutableQuadView materialBake(Material.Baked material, int bakeFlags) { + QuadSpriteBaker.bakeSprite(this, material.sprite(), bakeFlags); + materialInfo(ModelHelper.computeMaterialInfo(material, this)); + return this; + } + + // TODO: FRAPI 26.1 docs + default MutableQuadView materialInfo(BakedQuad.MaterialInfo materialInfo) { + QuadAtlas atlas = QuadAtlas.ofLocation(materialInfo.sprite().atlasLocation()); if (atlas == null) { atlas = QuadAtlas.BLOCK; } atlas(atlas); + chunkLayer(materialInfo.layer()); + itemRenderType(materialInfo.itemRenderType()); + tintIndex(materialInfo.tintIndex()); + diffuseShade(materialInfo.shade()); + int lightEmission = materialInfo.lightEmission(); + emissive(lightEmission == 15); + minLightmap(LightCoordsUtil.pack(lightEmission, lightEmission)); + animated(materialInfo.sprite().contents().isAnimated()); return this; } @@ -224,6 +278,20 @@ default MutableQuadView lightmap(int l0, int l1, int l2, int l3) { return this; } + /** + * Sets the minimum lightmap value for the whole quad; in other words, sets each vertex's + * lightmap value to the per-component maximum of its existing value and the given value. + * + * @param lightmap the minimum lightmap value + */ + default MutableQuadView minLightmap(int lightmap) { + lightmap(0, ExtraLightCoordsUtil.smoothMax(lightmap(0), lightmap)); + lightmap(1, ExtraLightCoordsUtil.smoothMax(lightmap(1), lightmap)); + lightmap(2, ExtraLightCoordsUtil.smoothMax(lightmap(2), lightmap)); + lightmap(3, ExtraLightCoordsUtil.smoothMax(lightmap(3), lightmap)); + return this; + } + /** * Sets the normal vector for the given vertex. The {@linkplain #faceNormal() face normal} is used when no vertex * normal is provided. Models that have per-vertex normals should include them to get correct lighting when it @@ -252,7 +320,7 @@ default MutableQuadView normal(int vertexIndex, Vector3fc normal) { * but if set, should be the expected value of {@link #lightFace()}. It may be used to shortcut geometric analysis, * if the provided value was correct; otherwise, it is ignored. * - *

The nominal face is also used for {@link #spriteBake(TextureAtlasSprite, int)} with {@link #BAKE_LOCK_UV}. + *

The nominal face is also used for {@link #materialBake(Material.Baked, int)} with {@link #BAKE_LOCK_UV}. * *

When {@link #cullFace(Direction)} is called, it also sets the nominal face. * @@ -278,17 +346,47 @@ default MutableQuadView normal(int vertexIndex, Vector3fc normal) { MutableQuadView cullFace(@Nullable Direction face); /** - * Controls how this quad's pixels should be blended with the scene. + * Sets the {@linkplain QuadAtlas atlas texture} used by this quad. This property is mainly used to retrieve this + * quad's {@linkplain TextureAtlasSprite sprite} via the appropriate atlas' {@link SpriteFinder}. + * + *

In block contexts, this property must be {@link QuadAtlas#BLOCK}. * - *

If set to {@code null}, {@link ItemBlockRenderTypes#getChunkRenderType(BlockState)} will be used to retrieve - * the {@linkplain ChunkSectionLayer chunk layer} in block contexts. Set to another value to override this behavior. + *

The default value is {@link QuadAtlas#BLOCK}. + * + * @see QuadAtlas + */ + MutableQuadView atlas(QuadAtlas quadAtlas); + + /** + * Controls how this quad should be rendered after buffering in block contexts. * - *

In block contexts, a non-null value will be used directly. In item contexts, any value will be converted to a - * {@link RenderType} using {@link FabricLayerRenderState#setRenderTypeGetter(ItemRenderTypeGetter)}. + *

The default value is {@link ChunkSectionLayer#CUTOUT}. * - *

The default value is {@code null}. + *

This property is respected only in block contexts. It will not have an effect in other contexts. + */ + MutableQuadView chunkLayer(ChunkSectionLayer layer); + + // TODO FRAPI 26.1: allow using any RenderType + + /** + * Controls how this quad should be rendered after buffering in item contexts. The atlas texture used by the set + * render type must match this quad's {@linkplain #atlas(QuadAtlas) atlas}. + * + *

Only the following values are allowed: + *

    + *
  • {@link Sheets#cutoutItemSheet()} + *
  • {@link Sheets#translucentItemSheet()} + *
  • {@link Sheets#cutoutBlockItemSheet()} + *
  • {@link Sheets#translucentBlockItemSheet()} + *
+ * + *

The behavior is undefined if this method is invoked with any value not in the above list. + * + *

The default value is {@link Sheets#cutoutBlockItemSheet()}. + * + *

This property is respected only in item contexts. It will not have an effect in other contexts. */ - MutableQuadView chunkLayer(@Nullable ChunkSectionLayer layer); + MutableQuadView itemRenderType(RenderType renderType); /** * When true, this quad will be rendered at full brightness. @@ -320,7 +418,7 @@ default MutableQuadView normal(int vertexIndex, Vector3fc normal) { *

If set to {@link TriState#DEFAULT}, ambient occlusion will be used if the block state has * {@linkplain BlockState#getLightEmission() a luminance} of 0. Set to {@link TriState#TRUE} or {@link TriState#FALSE} * to override this behavior. {@link TriState#TRUE} will not have an effect if - * {@linkplain Minecraft#useAmbientOcclusion() ambient occlusion is disabled globally}. + * {@linkplain OptionsRenderState#ambientOcclusion ambient occlusion is disabled globally}. * *

The default value is {@link TriState#DEFAULT}. * @@ -355,16 +453,11 @@ default MutableQuadView normal(int vertexIndex, Vector3fc normal) { MutableQuadView shadeMode(ShadeMode mode); /** - * Sets the {@linkplain QuadAtlas atlas texture} used by this quad. - * - *

In block contexts, this property must be {@link QuadAtlas#BLOCK}. In item contexts, this property will be - * converted to a {@link RenderType} using {@link FabricLayerRenderState#setRenderTypeGetter(ItemRenderTypeGetter)}. - * - *

The default value is {@link QuadAtlas#BLOCK}. + * Whether the sprite associated with this quad is animated. * - * @see QuadAtlas + *

The default value is {@code false}. */ - MutableQuadView atlas(QuadAtlas quadAtlas); + MutableQuadView animated(boolean animated); /** * Sets the tint index, which is used to retrieve the tint color. @@ -389,10 +482,82 @@ default MutableQuadView normal(int vertexIndex, Vector3fc normal) { MutableQuadView copyFrom(QuadView quad); /** - * Sets all applicable data and properties of this quad as specified by the given {@link BakedQuad}. In addition, - * this quad's vertex colors and vertex normals will be reset. This quad's existing lightmap values will be ignored. + * Sets all applicable data and properties of this quad as specified by the given {@link BakedQuad}, in accordance + * with {@link #materialInfo(BakedQuad.MaterialInfo)}. In addition, this quad's vertex colors and vertex normals + * will be reset. * *

Calling this method does not emit this quad. */ MutableQuadView fromBakedQuad(BakedQuad quad); + + /** + * Resets all vertex data and properties of this quad to their default values. + */ + MutableQuadView clear(); + + /** + * Tolerance for determining if the depth parameter to {@link #square(Direction, float, float, float, float, float)} + * is effectively zero - meaning the face is a cull face. + */ + float CULL_FACE_EPSILON = 0.00001f; + + /** + * Helper method to assign vertex coordinates for a square aligned with the given face. + * Ensures that vertex order is consistent with vanilla convention. (Incorrect order can + * lead to bad AO lighting unless enhanced lighting logic is available/enabled.) + * + *

Square will be parallel to the given face and coplanar with the face (and culled if the + * face is occluded) if the depth parameter is approximately zero. See {@link #CULL_FACE_EPSILON}. + * + *

All coordinates should be normalized (0-1). + */ + default MutableQuadView square(Direction nominalFace, float left, float bottom, float right, float top, float depth) { + if (Math.abs(depth) < CULL_FACE_EPSILON) { + cullFace(nominalFace); + depth = 0; // avoid any inconsistency for face quads + } else { + cullFace(null); + } + + nominalFace(nominalFace); + switch (nominalFace) { + case UP: + depth = 1 - depth; + top = 1 - top; + bottom = 1 - bottom; + + case DOWN: + pos(0, left, depth, top); + pos(1, left, depth, bottom); + pos(2, right, depth, bottom); + pos(3, right, depth, top); + break; + + case EAST: + depth = 1 - depth; + left = 1 - left; + right = 1 - right; + + case WEST: + pos(0, depth, top, left); + pos(1, depth, bottom, left); + pos(2, depth, bottom, right); + pos(3, depth, top, right); + break; + + case SOUTH: + depth = 1 - depth; + left = 1 - left; + right = 1 - right; + + case NORTH: + pos(0, 1 - left, top, depth); + pos(1, 1 - left, bottom, depth); + pos(2, 1 - right, bottom, depth); + pos(3, 1 - right, top, depth); + break; + } + + return this; + } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/mesh/QuadAtlas.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/mesh/QuadAtlas.java index dca0f755e05..7d5ecf80d73 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/mesh/QuadAtlas.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/mesh/QuadAtlas.java @@ -19,29 +19,32 @@ import org.jspecify.annotations.Nullable; import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.data.AtlasIds; import net.minecraft.resources.Identifier; /** * An atlas texture that a {@link QuadView} uses. */ public enum QuadAtlas { - BLOCK(TextureAtlas.LOCATION_BLOCKS), - ITEM(TextureAtlas.LOCATION_ITEMS); + BLOCK(TextureAtlas.LOCATION_BLOCKS, AtlasIds.BLOCKS), + ITEM(TextureAtlas.LOCATION_ITEMS, AtlasIds.ITEMS); - private final Identifier textureId; + private final Identifier textureLocation; + private final Identifier id; - QuadAtlas(Identifier textureId) { - this.textureId = textureId; + QuadAtlas(Identifier textureLocation, Identifier id) { + this.textureLocation = textureLocation; + this.id = id; } /** - * {@return the quad atlas for the given atlas texture ID or null if no corresponding quad atlas exists} + * {@return the quad atlas for the given atlas texture location or null if no corresponding quad atlas exists} */ @Nullable - public static QuadAtlas of(Identifier atlasTextureId) { - if (atlasTextureId.equals(TextureAtlas.LOCATION_BLOCKS)) { + public static QuadAtlas ofLocation(Identifier atlasTextureLocation) { + if (atlasTextureLocation.equals(TextureAtlas.LOCATION_BLOCKS)) { return BLOCK; - } else if (atlasTextureId.equals(TextureAtlas.LOCATION_ITEMS)) { + } else if (atlasTextureLocation.equals(TextureAtlas.LOCATION_ITEMS)) { return ITEM; } else { return null; @@ -49,9 +52,30 @@ public static QuadAtlas of(Identifier atlasTextureId) { } /** - * {@return the atlas texture ID} + * {@return the quad atlas for the given atlas ID or null if no corresponding quad atlas exists} */ - public Identifier getTextureId() { - return textureId; + @Nullable + public static QuadAtlas ofId(Identifier atlasId) { + if (atlasId.equals(AtlasIds.BLOCKS)) { + return BLOCK; + } else if (atlasId.equals(AtlasIds.ITEMS)) { + return ITEM; + } else { + return null; + } + } + + /** + * @return the atlas texture location (ends with {@code .png}) + */ + public Identifier getTextureLocation() { + return textureLocation; + } + + /** + * @return the atlas ID + */ + public Identifier getId() { + return id; } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/mesh/QuadEmitter.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/mesh/QuadEmitter.java index b2146601a47..3d5ddac61e6 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/mesh/QuadEmitter.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/mesh/QuadEmitter.java @@ -22,10 +22,11 @@ import org.joml.Vector3fc; import org.jspecify.annotations.Nullable; -import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.chunk.ChunkSectionLayer; import net.minecraft.client.renderer.item.ItemStackRenderState; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.rendertype.RenderType; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.Direction; import net.fabricmc.fabric.api.util.TriState; @@ -55,6 +56,12 @@ default QuadEmitter pos(int vertexIndex, Vector3fc pos) { return this; } + @Override + default QuadEmitter translate(float x, float y, float z) { + MutableQuadView.super.translate(x, y, z); + return this; + } + @Override QuadEmitter color(int vertexIndex, int color); @@ -64,6 +71,12 @@ default QuadEmitter color(int c0, int c1, int c2, int c3) { return this; } + @Override + default QuadEmitter multiplyColor(int color) { + MutableQuadView.super.multiplyColor(color); + return this; + } + @Override QuadEmitter uv(int vertexIndex, float u, float v); @@ -80,16 +93,20 @@ default QuadEmitter uv(int vertexIndex, Vector2fc uv) { } @Override - default QuadEmitter spriteBake(TextureAtlasSprite sprite, int bakeFlags) { - MutableQuadView.super.spriteBake(sprite, bakeFlags); + default MutableQuadView uvUnitSquare() { + MutableQuadView.super.uvUnitSquare(); return this; } - default QuadEmitter uvUnitSquare() { - uv(0, 0, 0); - uv(1, 0, 1); - uv(2, 1, 1); - uv(3, 1, 0); + @Override + default QuadEmitter materialBake(Material.Baked material, int bakeFlags) { + MutableQuadView.super.materialBake(material, bakeFlags); + return this; + } + + @Override + default QuadEmitter materialInfo(BakedQuad.MaterialInfo materialInfo) { + MutableQuadView.super.materialInfo(materialInfo); return this; } @@ -102,6 +119,11 @@ default QuadEmitter lightmap(int l0, int l1, int l2, int l3) { return this; } + default QuadEmitter minLightmap(int lightmap) { + MutableQuadView.super.minLightmap(lightmap); + return this; + } + @Override QuadEmitter normal(int vertexIndex, float x, float y, float z); @@ -124,7 +146,13 @@ default QuadEmitter normal(int vertexIndex, Vector3fc normal) { QuadEmitter cullFace(@Nullable Direction face); @Override - QuadEmitter chunkLayer(@Nullable ChunkSectionLayer layer); + QuadEmitter atlas(QuadAtlas quadAtlas); + + @Override + QuadEmitter chunkLayer(ChunkSectionLayer layer); + + @Override + QuadEmitter itemRenderType(RenderType renderType); @Override QuadEmitter emissive(boolean emissive); @@ -142,7 +170,7 @@ default QuadEmitter normal(int vertexIndex, Vector3fc normal) { QuadEmitter shadeMode(ShadeMode mode); @Override - QuadEmitter atlas(QuadAtlas quadAtlas); + QuadEmitter animated(boolean animated); @Override QuadEmitter tintIndex(int tintIndex); @@ -156,69 +184,12 @@ default QuadEmitter normal(int vertexIndex, Vector3fc normal) { @Override QuadEmitter fromBakedQuad(BakedQuad quad); - /** - * Tolerance for determining if the depth parameter to {@link #square(Direction, float, float, float, float, float)} - * is effectively zero - meaning the face is a cull face. - */ - float CULL_FACE_EPSILON = 0.00001f; + @Override + QuadEmitter clear(); - /** - * Helper method to assign vertex coordinates for a square aligned with the given face. - * Ensures that vertex order is consistent with vanilla convention. (Incorrect order can - * lead to bad AO lighting unless enhanced lighting logic is available/enabled.) - * - *

Square will be parallel to the given face and coplanar with the face (and culled if the - * face is occluded) if the depth parameter is approximately zero. See {@link #CULL_FACE_EPSILON}. - * - *

All coordinates should be normalized (0-1). - */ + @Override default QuadEmitter square(Direction nominalFace, float left, float bottom, float right, float top, float depth) { - if (Math.abs(depth) < CULL_FACE_EPSILON) { - cullFace(nominalFace); - depth = 0; // avoid any inconsistency for face quads - } else { - cullFace(null); - } - - nominalFace(nominalFace); - switch (nominalFace) { - case UP: - depth = 1 - depth; - top = 1 - top; - bottom = 1 - bottom; - - case DOWN: - pos(0, left, depth, top); - pos(1, left, depth, bottom); - pos(2, right, depth, bottom); - pos(3, right, depth, top); - break; - - case EAST: - depth = 1 - depth; - left = 1 - left; - right = 1 - right; - - case WEST: - pos(0, depth, top, left); - pos(1, depth, bottom, left); - pos(2, depth, bottom, right); - pos(3, depth, top, right); - break; - - case SOUTH: - depth = 1 - depth; - left = 1 - left; - right = 1 - right; - - case NORTH: - pos(0, 1 - left, top, depth); - pos(1, 1 - left, bottom, depth); - pos(2, 1 - right, bottom, depth); - pos(3, 1 - right, top, depth); - break; - } - + MutableQuadView.super.square(nominalFace, left, bottom, right, top, depth); return this; } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/mesh/QuadView.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/mesh/QuadView.java index 6b480d2d71e..e914253ed03 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/mesh/QuadView.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/mesh/QuadView.java @@ -16,19 +16,24 @@ package net.fabricmc.fabric.api.client.renderer.v1.mesh; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.QuadInstance; +import com.mojang.blaze3d.vertex.VertexConsumer; import org.joml.Vector2f; import org.joml.Vector3f; import org.joml.Vector3fc; import org.jspecify.annotations.Nullable; import net.minecraft.client.model.geom.builders.UVPair; -import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.chunk.ChunkSectionLayer; import net.minecraft.client.renderer.item.ItemStackRenderState; +import net.minecraft.client.renderer.rendertype.RenderType; import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.Direction; -import net.minecraft.util.LightCoordsUtil; +import net.fabricmc.fabric.api.client.renderer.v1.model.ModelHelper; import net.fabricmc.fabric.api.client.renderer.v1.sprite.SpriteFinder; import net.fabricmc.fabric.api.util.TriState; @@ -154,19 +159,28 @@ public interface QuadView { @Nullable Direction cullFace(); + /** + * @see MutableQuadView#atlas(QuadAtlas) + */ + QuadAtlas atlas(); + /** * @see MutableQuadView#chunkLayer(ChunkSectionLayer) */ - @Nullable ChunkSectionLayer chunkLayer(); + /** + * @see MutableQuadView#itemRenderType(RenderType) + */ + RenderType itemRenderType(); + /** * @see MutableQuadView#emissive(boolean) */ boolean emissive(); /** - * This method is equivalent to {@link BakedQuad#shade()}. + * This method is equivalent to {@link BakedQuad.MaterialInfo#shade()}. * * @see MutableQuadView#diffuseShade(boolean) */ @@ -188,12 +202,12 @@ public interface QuadView { ShadeMode shadeMode(); /** - * @see MutableQuadView#atlas(QuadAtlas) + * @see MutableQuadView#animated(boolean) */ - QuadAtlas atlas(); + boolean animated(); /** - * This method is equivalent to {@link BakedQuad#tintIndex()}. + * This method is equivalent to {@link BakedQuad.MaterialInfo#tintIndex()}. * * @see MutableQuadView#tintIndex(int) */ @@ -210,7 +224,7 @@ public interface QuadView { * @param sprite The sprite is not serialized so it must be provided by the caller. Retrieve it using * {@link SpriteFinder#find(QuadView)} if it is not already known. */ - default BakedQuad toBakedQuad(BakedQuad.SpriteInfo sprite) { + default BakedQuad toBakedQuad(TextureAtlasSprite sprite) { Vector3f position0 = copyPos(0, null); Vector3f position1 = copyPos(1, null); Vector3f position2 = copyPos(2, null); @@ -220,24 +234,7 @@ default BakedQuad toBakedQuad(BakedQuad.SpriteInfo sprite) { long packedUV2 = UVPair.pack(u(2), v(2)); long packedUV3 = UVPair.pack(u(3), v(3)); - // The light emission is set to 15 if the quad is emissive; otherwise, to the minimum of all four sky light - // values and all four block light values. - int lightEmission = 15; - - if (!emissive()) { - for (int i = 0; i < 4; i++) { - int lightmap = lightmap(i); - - if (lightmap == 0) { - lightEmission = 0; - break; - } - - int blockLight = LightCoordsUtil.block(lightmap); - int skyLight = LightCoordsUtil.sky(lightmap); - lightEmission = Math.min(lightEmission, Math.min(blockLight, skyLight)); - } - } + BakedQuad.MaterialInfo materialInfo = ModelHelper.computeMaterialInfo(new Material.Baked(sprite, false), this); return new BakedQuad( position0, @@ -248,11 +245,38 @@ default BakedQuad toBakedQuad(BakedQuad.SpriteInfo sprite) { packedUV1, packedUV2, packedUV3, - tintIndex(), lightFace(), - sprite, - diffuseShade(), - lightEmission + materialInfo ); } + + /** + * Buffers this quad's vertex data into the given {@link VertexConsumer} without any additional + * transformations. The given overlay value will be applied to all output vertices as + * {@link QuadView}s don't store overlay values. + * + *

Unlike + * {@link VertexConsumer#putBlockBakedQuad(float, float, float, BakedQuad, QuadInstance)}, + * output vertex normals are based on the {@linkplain #faceNormal() exact face normal} or set + * vertex normals instead of the {@linkplain #lightFace() quantized face normal}. + * + * @param overlayCoords the overlay value to use for all output vertices + * @param vertexConsumer the vertex consumer to output to + */ + void buffer(int overlayCoords, VertexConsumer vertexConsumer); + + /** the given {@link VertexConsumer} with an additional + * transformation. The given overlay value will be applied to all output vertices as + * {@link QuadView}s don't store overlay values. + * + *

Unlike {@link VertexConsumer#putBakedQuad(PoseStack.Pose, BakedQuad, QuadInstance)}, + * output vertex normals are based on the {@linkplain #faceNormal() exact face normal} or set + * vertex normals instead of the + * * Buffers this quad's vertex data into{@linkplain #lightFace() quantized face normal}. + * + * @param overlayCoords the overlay value to use for all output vertices + * @param pose the transformation to apply to output vertices + * @param vertexConsumer the vertex consumer to output to + */ + void buffer(int overlayCoords, PoseStack.Pose pose, VertexConsumer vertexConsumer); } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockStateModel.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockStateModel.java index 71f65c1d464..2d1ff5fabf9 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockStateModel.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockStateModel.java @@ -16,25 +16,32 @@ package net.fabricmc.fabric.api.client.renderer.v1.model; +import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; import org.jspecify.annotations.Nullable; -import net.minecraft.client.renderer.block.model.BlockModelPart; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.block.model.multipart.MultiPartModel; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.ModelBlockRenderer; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart; +import net.minecraft.client.renderer.block.dispatch.multipart.MultiPartModel; +import net.minecraft.client.renderer.chunk.ChunkSectionLayer; +import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.EmptyBlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; import net.fabricmc.fabric.api.client.renderer.v1.mesh.MutableQuadView; import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter; +// TODO FRAPI 26.1: +// problem: models that rely on level context need to generalize their flags, which can be very inefficient, as flags cannot depend on context. +// case: models that can render an arbitrary submodel, such as the testmod's frame model. +// solution: make an overloaded flag getter that accepts context AND/OR allow emitQuads to return the flags for the current context. /** * Interface for baked block state models that output geometry with enhanced rendering features. * Can also be used to generate or customize geometry output based on level state. @@ -46,15 +53,15 @@ public interface FabricBlockStateModel { /** * Produces this model's geometry. This method must be called instead of - * {@link BlockStateModel#collectParts(RandomSource, List)} or {@link BlockStateModel#collectParts(RandomSource)}; the vanilla methods + * {@link BlockStateModel#collectParts(RandomSource, List)}; the vanilla method * should be considered deprecated as they may not produce accurate results. However, it is acceptable for a - * custom model to only implement the vanilla methods as the default implementation of this method will delegate to - * one of the vanilla methods. + * custom model to only implement the vanilla method as the default implementation of this method will delegate to + * it. * *

Like {@link BlockStateModel#collectParts(RandomSource, List)}, this method may be called outside of chunk rebuilds. For * example, some entities and block entities render blocks. In some such cases, the provided position may be the * nearest position and not actual position. In others, the provided level may be - * {@linkplain EmptyBlockAndTintGetter#INSTANCE empty}. + * {@linkplain BlockAndTintGetter#EMPTY empty}. * *

If multiple independent subtasks use the provided random, it is recommended that implementations * {@linkplain RandomSource#setSeed(long) reseed} the random using a predetermined value before invoking each subtask, so @@ -83,12 +90,27 @@ public interface FabricBlockStateModel { * @see #createGeometryKey(BlockAndTintGetter, BlockPos, BlockState, RandomSource) */ default void emitQuads(QuadEmitter emitter, BlockAndTintGetter level, BlockPos pos, BlockState state, RandomSource random, Predicate<@Nullable Direction> cullTest) { - final List parts = ((BlockStateModel) this).collectParts(random); + final boolean cutoutLeaves = Minecraft.getInstance().options.cutoutLeaves().get(); + final boolean forceOpaque = ModelBlockRenderer.forceOpaque(cutoutLeaves, state); + + if (forceOpaque) { + emitter.pushTransform(quad -> { + quad.chunkLayer(ChunkSectionLayer.SOLID); + return true; + }); + } + + final List parts = new ArrayList<>(); + ((BlockStateModel) this).collectParts(random, parts); final int partCount = parts.size(); for (int i = 0; i < partCount; i++) { parts.get(i).emitQuads(emitter, cullTest); } + + if (forceOpaque) { + emitter.popTransform(); + } } /** @@ -102,7 +124,7 @@ default void emitQuads(QuadEmitter emitter, BlockAndTintGetter level, BlockPos p * just those produced by this model instance, so care should be taken when selecting the type of the key. * Generally, one class of model will want to make its own record class to use for geometry keys. * - *

A {@code null} key means that a geometry key does exist for specifically the given context; a key may exist + *

A {@code null} key means that a geometry key does not exist for specifically the given context; a key may exist * for a different context. It is always possible to create a key for any context, but some custom models may choose * not to if doing so is too complex. Vanilla models correctly implement this method, but may return {@code null} * when delegating to a submodel that returns {@code null}. @@ -122,7 +144,7 @@ default Object createGeometryKey(BlockAndTintGetter level, BlockPos pos, BlockSt } /** - * Extension of {@link BlockStateModel#particleIcon()} that accepts level state. This method will be invoked most + * Extension of {@link BlockStateModel#particleMaterial()} that accepts level state. This method will be invoked most * of the time, but the vanilla method may still be invoked when no level context is available. * *

If your model delegates to other {@link BlockStateModel}s, ensure that it also delegates invocations of @@ -130,11 +152,11 @@ default Object createGeometryKey(BlockAndTintGetter level, BlockPos pos, BlockSt * * @param level The level in which the block exists. * @param pos The position of the block in the level. - * @param state The block state whose model was queried for the particle sprite. This is not guaranteed to be the + * @param state The block state whose model was queried for the particle material. This is not guaranteed to be the * state corresponding to {@code this} model! - * @return the particle sprite + * @return the particle material */ - default TextureAtlasSprite particleIcon(BlockAndTintGetter level, BlockPos pos, BlockState state) { - return ((BlockStateModel) this).particleIcon(); + default Material.Baked particleMaterial(BlockAndTintGetter level, BlockPos pos, BlockState state) { + return ((BlockStateModel) this).particleMaterial(); } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockModelPart.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockStateModelPart.java similarity index 82% rename from fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockModelPart.java rename to fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockStateModelPart.java index 96e46ebc126..5d7fe9f1c08 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockModelPart.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockStateModelPart.java @@ -20,23 +20,23 @@ import org.jspecify.annotations.Nullable; -import net.minecraft.client.renderer.block.model.BlockModelPart; +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter; import net.fabricmc.fabric.impl.client.renderer.VanillaBlockModelPartEncoder; /** - * Note: This interface is automatically implemented on {@link BlockModelPart} via Mixin and interface injection. + * Note: This interface is automatically implemented on {@link BlockStateModelPart} via Mixin and interface injection. */ -public interface FabricBlockModelPart { +public interface FabricBlockStateModelPart { /** * Produces this model part's geometry. This method must be called instead of - * {@link BlockModelPart#getQuads(Direction)} and {@link BlockModelPart#useAmbientOcclusion()}; the vanilla methods + * {@link BlockStateModelPart#getQuads(Direction)} and {@link BlockStateModelPart#useAmbientOcclusion()}; the vanilla methods * should be considered deprecated as they may not produce accurate results. However, it is acceptable for a * custom model part to only implement the vanilla methods as the default implementation of this method will * delegate to the vanilla methods. @@ -44,7 +44,7 @@ public interface FabricBlockModelPart { *

This method mainly exists for convenience when interacting with parts implemented and produced by vanilla * code. Custom models should generally override * {@link FabricBlockStateModel#emitQuads(QuadEmitter, BlockAndTintGetter, BlockPos, BlockState, RandomSource, Predicate)} - * instead of subclassing {@link BlockModelPart} and overriding this method. + * instead of subclassing {@link BlockStateModelPart} and overriding this method. * * @param emitter Accepts model part output. * @param cullTest A test that returns {@code true} for faces which will be culled and {@code false} for faces which @@ -54,6 +54,6 @@ public interface FabricBlockModelPart { * should be used whenever possible. */ default void emitQuads(QuadEmitter emitter, Predicate<@Nullable Direction> cullTest) { - VanillaBlockModelPartEncoder.emitQuads((BlockModelPart) this, emitter, cullTest); + VanillaBlockModelPartEncoder.emitQuads((BlockStateModelPart) this, emitter, cullTest); } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockModelShaper.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockStateModelSet.java similarity index 61% rename from fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockModelShaper.java rename to fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockStateModelSet.java index f23c4ab3051..d77d78580e4 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockModelShaper.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockStateModelSet.java @@ -16,32 +16,31 @@ package net.fabricmc.fabric.api.client.renderer.v1.model; -import net.minecraft.client.renderer.block.BlockModelShaper; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.BlockStateModelSet; +import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.EmptyBlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; /** - * Note: This interface is automatically implemented on {@link BlockModelShaper} via Mixin and interface injection. + * Note: This interface is automatically implemented on {@link BlockStateModelSet} via Mixin and interface injection. */ -public interface FabricBlockModelShaper { +public interface FabricBlockStateModelSet { /** - * Alternative for {@link BlockModelShaper#getParticleIcon(BlockState)} that additionally accepts a + * Alternative for {@link BlockStateModelSet#getParticleMaterial(BlockState)} that additionally accepts a * {@link BlockAndTintGetter} and {@link BlockPos} to invoke - * {@link FabricBlockStateModel#particleIcon(BlockAndTintGetter, BlockPos, BlockState)}. Prefer using this method - * over the vanilla alternative when applicable to correctly retrieve context-aware particle sprites. If level + * {@link FabricBlockStateModel#particleMaterial(BlockAndTintGetter, BlockPos, BlockState)}. Prefer using this method + * over the vanilla alternative when applicable to correctly retrieve context-aware particle materials. If level * context is not available, use the vanilla method instead of passing empty level context to this method. * - * @param state The block state whose model to retrieve the particle sprite from. + * @param state The block state whose model to retrieve the particle material from. * @param level The level in which the block exists. Should not be empty (i.e. not - * {@link EmptyBlockAndTintGetter}). + * {@link BlockAndTintGetter#EMPTY}). * @param pos The position of the block in the level. - * @return the particle sprite + * @return the particle material */ - default TextureAtlasSprite getParticleIcon(BlockState state, BlockAndTintGetter level, BlockPos pos) { - return ((BlockModelShaper) this).getBlockModel(state).particleIcon( + default Material.Baked getParticleMaterial(BlockState state, BlockAndTintGetter level, BlockPos pos) { + return ((BlockStateModelSet) this).get(state).particleMaterial( level, pos, state); } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/MeshQuadCollection.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/MeshQuadCollection.java index 6c3fbaf1578..b34d397faed 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/MeshQuadCollection.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/MeshQuadCollection.java @@ -17,27 +17,32 @@ package net.fabricmc.fabric.api.client.renderer.v1.model; import java.util.List; +import java.util.function.Consumer; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.block.model.TextureSlots; +import net.minecraft.client.renderer.block.dispatch.ModelState; import net.minecraft.client.resources.model.ModelBaker; import net.minecraft.client.resources.model.ModelDebugName; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.QuadCollection; -import net.minecraft.client.resources.model.UnbakedGeometry; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.geometry.QuadCollection; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.resources.model.sprite.TextureSlots; import net.fabricmc.fabric.api.client.renderer.v1.mesh.Mesh; +import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadView; /** * A special {@link QuadCollection} which hides a {@link Mesh} instead of using {@link BakedQuad}s. Useful for custom - * implementations of {@link UnbakedGeometry#bake(TextureSlots, ModelBaker, ModelState, ModelDebugName)} that want to return a - * mesh. Instances of this class always return empty lists from inherited methods. + * implementations of {@link UnbakedGeometry#bake(TextureSlots, ModelBaker, ModelState, ModelDebugName)} that want to + * return a mesh. Instances of this class always return empty quad lists from inherited methods. Other public methods, + * including {@link QuadCollection#materialFlags()} and {@link QuadCollection#hasMaterialFlag(int)}, will return + * expected values computed from the mesh. * - *

Any code that interacts with {@link QuadCollection} should first check {@code instanceof MeshBakedGeometry} and use - * {@link #getMesh()} if {@code true} or the vanilla methods otherwise. + *

Any code that interacts with {@link QuadCollection} should first check {@code instanceof MeshQuadCollection} and + * use {@link #getMesh()} if {@code true} or the vanilla methods otherwise. */ public final class MeshQuadCollection extends QuadCollection { private final Mesh mesh; + private @BakedQuad.MaterialFlags int materialFlags = -1; public MeshQuadCollection(Mesh mesh) { super(List.of(), List.of(), List.of(), List.of(), List.of(), List.of(), List.of(), List.of()); @@ -50,4 +55,33 @@ public MeshQuadCollection(Mesh mesh) { public Mesh getMesh() { return mesh; } + + private static @BakedQuad.MaterialFlags int computeMaterialFlags(final Mesh mesh) { + var quadConsumer = new Consumer() { + @BakedQuad.MaterialFlags int flags = 0; + + @Override + public void accept(QuadView quad) { + if (quad.chunkLayer().translucent()) { + flags |= BakedQuad.FLAG_TRANSLUCENT; + } + + if (quad.animated()) { + flags |= BakedQuad.FLAG_ANIMATED; + } + } + }; + + mesh.forEach(quadConsumer); + return quadConsumer.flags; + } + + @Override + public @BakedQuad.MaterialFlags int materialFlags() { + if (materialFlags == -1) { + materialFlags = computeMaterialFlags(mesh); + } + + return materialFlags; + } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/ModelHelper.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/ModelHelper.java index 06b385d684f..e09f2f59e02 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/ModelHelper.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/ModelHelper.java @@ -17,18 +17,17 @@ package net.fabricmc.fabric.api.client.renderer.v1.model; import java.util.Arrays; -import java.util.List; -import com.google.common.collect.ImmutableList; +import com.mojang.blaze3d.platform.Transparency; import org.jspecify.annotations.Nullable; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.Direction; -import net.minecraft.data.AtlasIds; +import net.minecraft.util.LightCoordsUtil; -import net.fabricmc.fabric.api.client.renderer.v1.mesh.Mesh; -import net.fabricmc.fabric.api.client.renderer.v1.sprite.SpriteFinder; +import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadView; /** * Collection of utilities for model implementations. @@ -64,35 +63,99 @@ public static Direction faceFromIndex(int faceIndex) { } /** - * Converts a mesh into an array of lists of vanilla baked quads. - * Useful for creating vanilla baked models when required for compatibility. - * The array indexes correspond to {@link Direction#getName()} with the - * addition of {@link #NULL_FACE_ID}. - * - *

Retrieves sprites from the block texture atlas via {@link SpriteFinder}. + * Computes the {@link BakedQuad.MaterialInfo} for a {@link Material.Baked}, using the vertex + * UVs from the given quad. */ - public static List[] toQuadLists(Mesh mesh) { - SpriteFinder finder = Minecraft.getInstance().getAtlasManager().getAtlasOrThrow(AtlasIds.BLOCKS).spriteFinder(); - - @SuppressWarnings("unchecked") - final ImmutableList.Builder[] builders = new ImmutableList.Builder[7]; + public static BakedQuad.MaterialInfo computeMaterialInfo(Material.Baked material, QuadView quad) { + Transparency transparency = material.forceTranslucent() ? Transparency.TRANSLUCENT : computeTransparency(material.sprite(), quad); + // TODO: Consider interning or some other caching scheme to reduce object churn + return BakedQuad.MaterialInfo.of(material, transparency, quad.tintIndex(), quad.diffuseShade(), approximateLightEmission(quad)); + } - for (int i = 0; i < 7; i++) { - builders[i] = ImmutableList.builder(); + /** + * Computes the approximate + * {@linkplain BakedQuad.MaterialInfo#lightEmission() vanilla light emission} for the given + * quad. {@link QuadView}s store lightmap values per vertex, so a single vanilla light emission + * value cannot accurately represent a {@link QuadView}'s light data. + * + *

The approximate value is computed as 15 (the maximum) if the quad is emissive; otherwise, + * as the minimum of all four sky light values and all four block light values. + * + * @return the approximate light emission + */ + public static int approximateLightEmission(QuadView quad) { + int lightEmission = 15; + + if (!quad.emissive()) { + for (int i = 0; i < 4; i++) { + int lightmap = quad.lightmap(i); + + if (lightmap == 0) { + lightEmission = 0; + break; + } + + int blockLight = LightCoordsUtil.block(lightmap); + int skyLight = LightCoordsUtil.sky(lightmap); + lightEmission = Math.min(lightEmission, Math.min(blockLight, skyLight)); + } } - mesh.forEach(q -> { - Direction cullFace = q.cullFace(); - builders[cullFace == null ? NULL_FACE_ID : cullFace.get3DDataValue()].add(q.toBakedQuad(finder.find(q))); - }); - - @SuppressWarnings("unchecked") - List[] result = new List[7]; + return lightEmission; + } - for (int i = 0; i < 7; i++) { - result[i] = builders[i].build(); + /** + * Computes the {@link Transparency} for a {@link TextureAtlasSprite}, using the vertex UVs from + * the given quad. + */ + public static Transparency computeTransparency(TextureAtlasSprite sprite, QuadView quad) { + // Find the minimum and maximum UV's. + // A simulation of the algorithm is provided in comments below. + float minU = Float.MAX_VALUE; // 7, 7, 5, 3 + float minV = Float.MAX_VALUE; // 9, 8, 8, 8 + float maxU = 0; // 7, 12, 12, 12 + float maxV = 0; // 9, 9, 10, 13 + + // u, v + // 7, 9 + // 12,8 + // 5, 10 + // 3, 13 + + for (int i = 0; i < 4; i++) { + float u = quad.u(i); + float v = quad.v(i); + + if (u < minU) { + minU = u; + } + + if (u > maxU) { + maxU = u; + } + + if (v < minV) { + minV = v; + } + + if (v > maxV) { + maxV = v; + } } - return result; + // Normalize UVs + // Inverse linear interpolation + // `(t_q - t_0)/Δt` where `t_q` is the value and `t` is `u` or `v` + final float width = 1.0f / (sprite.getU1() - sprite.getU0()); + final float height = 1.0f / (sprite.getV1() - sprite.getV0()); + minU = (minU - sprite.getU0()) * width; + minV = (minV - sprite.getV0()) * height; + maxU = (maxU - sprite.getU0()) * width; + maxV = (maxV - sprite.getV0()) * height; + + // See FaceBakery#computeMaterialTransparency + return sprite + .contents() + .computeTransparency(minU, minV, maxU, maxV); } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/ModelStateHelper.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/ModelStateHelper.java index 540297210d8..6e5a756dc8a 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/ModelStateHelper.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/model/ModelStateHelper.java @@ -27,10 +27,10 @@ import org.joml.Vector3f; import org.joml.Vector4f; +import net.minecraft.client.renderer.block.dispatch.BlockModelRotation; +import net.minecraft.client.renderer.block.dispatch.ModelState; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.BlockModelRotation; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.UnbakedGeometry; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; import net.minecraft.core.BlockMath; import net.minecraft.core.Direction; diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/AltModelBlockRenderer.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/AltModelBlockRenderer.java new file mode 100644 index 00000000000..451b374e14f --- /dev/null +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/AltModelBlockRenderer.java @@ -0,0 +1,49 @@ +/* + * 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 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.dispatch.BlockStateModel; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; + +import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter; + +/** + * An alternative to {@link ModelBlockRenderer} that tessellates block models into a + * {@link QuadEmitter} instead of a {@link BlockQuadOutput}. + */ +public interface AltModelBlockRenderer { + /** + * An alternative to {@link ModelBlockRenderer#tesselateBlock(BlockQuadOutput, float, float, float, BlockAndTintGetter, BlockPos, BlockState, BlockStateModel, long)} + * that tessellates a {@link BlockStateModel} into a {@link QuadEmitter} instead of a + * {@link BlockQuadOutput}. + * + * @param output the quad output + * @param x the x position offset + * @param y the y position offset + * @param z the z position offset + * @param level the level to tessellate in + * @param pos the model's in-level position + * @param blockState the model's block state + * @param model the model + * @param seed the model's random seed + */ + void tesselateBlock(QuadEmitter output, float x, float y, float z, BlockAndTintGetter level, BlockPos pos, BlockState blockState, BlockStateModel model, long seed); +} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/BlockMultiBufferSource.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/BlockMultiBufferSource.java deleted file mode 100644 index 9dc403b7ef4..00000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/BlockMultiBufferSource.java +++ /dev/null @@ -1,33 +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 com.mojang.blaze3d.vertex.VertexConsumer; - -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; -import net.minecraft.client.renderer.rendertype.RenderType; - -/** - * Like {@link MultiBufferSource}, but takes {@link ChunkSectionLayer} instead of {@link RenderType}. Primarily - * used to correctly render block models which have geometry on more than one layer. - * - * @see FabricModelBlockRenderer - */ -public interface BlockMultiBufferSource { - VertexConsumer getBuffer(ChunkSectionLayer layer); -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/ChunkSectionLayerHelper.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/ChunkSectionLayerHelper.java index 92dce135660..fdcde5e11bf 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/ChunkSectionLayerHelper.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/ChunkSectionLayerHelper.java @@ -16,22 +16,16 @@ package net.fabricmc.fabric.api.client.renderer.v1.render; -import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.Sheets; import net.minecraft.client.renderer.chunk.ChunkSectionLayer; import net.minecraft.client.renderer.rendertype.RenderType; import net.minecraft.client.renderer.rendertype.RenderTypes; -import net.minecraft.world.level.block.state.BlockState; public final class ChunkSectionLayerHelper { private ChunkSectionLayerHelper() { } - /** - * Same logic as {@link net.minecraft.client.renderer.ItemBlockRenderTypes#getMovingBlockRenderType}, but accepts a {@link ChunkSectionLayer} instead of a - * {@link BlockState}. - */ - public static RenderType getMovingBlockLayer(ChunkSectionLayer layer) { + public static RenderType getMovingBlockRenderType(ChunkSectionLayer layer) { return switch (layer) { case SOLID -> RenderTypes.solidMovingBlock(); case CUTOUT -> RenderTypes.cutoutMovingBlock(); @@ -39,27 +33,7 @@ public static RenderType getMovingBlockLayer(ChunkSectionLayer layer) { }; } - /** - * Same logic as {@link net.minecraft.client.renderer.ItemBlockRenderTypes#getRenderType}, but accepts a {@link ChunkSectionLayer} instead of a - * {@link BlockState}. - */ - public static RenderType getEntityBlockLayer(ChunkSectionLayer layer) { - return layer == ChunkSectionLayer.TRANSLUCENT ? Sheets.translucentBlockItemSheet() : Sheets.cutoutBlockSheet(); - } - - /** - * Wraps the given provider, converting {@link ChunkSectionLayer}s to render types using - * {@link #getMovingBlockLayer(ChunkSectionLayer)}. - */ - public static BlockMultiBufferSource movingDelegate(MultiBufferSource bufferSource) { - return layer -> bufferSource.getBuffer(ChunkSectionLayerHelper.getMovingBlockLayer(layer)); - } - - /** - * Wraps the given provider, converting {@link ChunkSectionLayer}s to render types using - * {@link #getEntityBlockLayer(ChunkSectionLayer)}. - */ - public static BlockMultiBufferSource entityDelegate(MultiBufferSource bufferSource) { - return layer -> bufferSource.getBuffer(ChunkSectionLayerHelper.getEntityBlockLayer(layer)); + public static RenderType getRenderType(boolean translucent) { + return translucent ? Sheets.translucentBlockSheet() : Sheets.cutoutBlockSheet(); } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/ExtraLightCoordsUtil.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/ExtraLightCoordsUtil.java new file mode 100644 index 00000000000..740c4bd019f --- /dev/null +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/ExtraLightCoordsUtil.java @@ -0,0 +1,40 @@ +/* + * 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 net.minecraft.util.LightCoordsUtil; + +/** + * Covers some light-related utilities that {@link LightCoordsUtil} does not. + */ +public final class ExtraLightCoordsUtil { + private ExtraLightCoordsUtil() { + } + + /** + * @param coords1 Packed block- and skylight 1 + * @param coords2 Packed block- and skylight 2 + * @return The maximum block- and skylight of the two inputs, packed "smoothly". + */ + public static int smoothMax(final int coords1, final int coords2) { + int block1 = LightCoordsUtil.smoothBlock(coords1); + int block2 = LightCoordsUtil.smoothBlock(coords2); + int sky1 = LightCoordsUtil.smoothSky(coords1); + int sky2 = LightCoordsUtil.smoothSky(coords2); + return LightCoordsUtil.smoothPack(Math.max(block1, block2), Math.max(sky1, sky2)); + } +} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricBlockModelRenderState.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricBlockModelRenderState.java new file mode 100644 index 00000000000..4f8a17f8775 --- /dev/null +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricBlockModelRenderState.java @@ -0,0 +1,52 @@ +/* + * 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.function.Predicate; + +import org.joml.Matrix4fc; + +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.BlockModelRenderState; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; +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.mesh.QuadEmitter; + +/** + * Note: This interface is automatically implemented on {@link BlockModelRenderState} via Mixin and interface injection. + */ +public interface FabricBlockModelRenderState { + // TODO FRAPI 26.1: docs + // also the design here is not ideal because both setupModel and setupMesh override the transformation and renderType fields. + // if a user wants to use both methods, that's unnecessary and unintuitive. might not be worth changing as the part list is always initialized by setupModel. + /** + * Alternative to {@link BlockModelRenderState#setupModel(Matrix4fc, boolean)} that returns a + * {@link QuadEmitter}. + * + *

This method should be used in favor of the vanilla one in order to support modded models. + * The vanilla method is therefore considered deprecated. + * + * @return an emitter to use with {@link BlockStateModel#emitQuads}. + * @see BlockStateModel#emitQuads(QuadEmitter, BlockAndTintGetter, BlockPos, BlockState, RandomSource, Predicate) + */ + default QuadEmitter setupMesh(Matrix4fc transformation, boolean hasTranslucency) { + throw new IllegalStateException("Implemented via Mixin."); + } +} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricBlockRenderDispatcher.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricBlockRenderDispatcher.java deleted file mode 100644 index 515fd8f4f24..00000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricBlockRenderDispatcher.java +++ /dev/null @@ -1,97 +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.function.Predicate; - -import com.mojang.blaze3d.vertex.PoseStack; - -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.block.BlockRenderDispatcher; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; -import net.minecraft.core.BlockPos; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.EmptyBlockAndTintGetter; -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.QuadEmitter; - -/** - * Note: This interface is automatically implemented on {@link BlockRenderDispatcher} via Mixin and interface injection. - */ -public interface FabricBlockRenderDispatcher { - /** - * Alternative for - * {@link BlockRenderDispatcher#renderSingleBlock(BlockState, PoseStack, MultiBufferSource, int, int)} that - * additionally accepts the {@link BlockAndTintGetter} and {@link BlockPos} to pass to - * {@link BlockStateModel#emitQuads(QuadEmitter, BlockAndTintGetter, BlockPos, BlockState, RandomSource, Predicate)} - * when necessary. Prefer using this method over the vanilla alternative to correctly buffer models that have - * geometry on multiple chunk layers and to provide the model with additional context. - * - *

This method allows buffering a block model with minimal transformations to the model geometry. Usually used by - * entity renderers. - * - * @param state The block state. - * @param poseStack The pose stack. - * @param bufferSource The buffer source. - * @param layerFilter Specifies the chunk layers for which geometry should be buffered ({@code true}) or discarded - * ({@code false}). - * @param light The minimum light value. - * @param overlay The overlay value. - * @param level The level in which to render the model. Can be empty (i.e. {@link EmptyBlockAndTintGetter}). - * @param pos The position of the block in the level. Should be {@link BlockPos#ZERO} if the level is empty. - * - * - * @see FabricOrderedSubmitNodeCollector#submitBlock(PoseStack, BlockState, int, int, int, BlockAndTintGetter, BlockPos) - */ - default void renderSingleBlock(BlockState state, PoseStack poseStack, MultiBufferSource bufferSource, Predicate layerFilter, int light, int overlay, BlockAndTintGetter level, BlockPos pos) { - Renderer.get().renderSingleBlock((BlockRenderDispatcher) this, state, - poseStack, bufferSource, layerFilter, light, overlay, - level, pos); - } - - /** - * Alternative for - * {@link BlockRenderDispatcher#renderSingleBlock(BlockState, PoseStack, MultiBufferSource, int, int)} that - * additionally accepts the {@link BlockAndTintGetter} and {@link BlockPos} to pass to - * {@link BlockStateModel#emitQuads(QuadEmitter, BlockAndTintGetter, BlockPos, BlockState, RandomSource, Predicate)} - * when necessary. Prefer using this method over the vanilla alternative to correctly buffer models that have - * geometry on multiple chunk layers and to provide the model with additional context. - * - *

This method allows buffering a block model with minimal transformations to the model geometry. Usually used by - * entity renderers. - * - * @param state The block state. - * @param poseStack The pose stack. - * @param bufferSource The buffer source. - * @param light The minimum light value. - * @param overlay The overlay value. - * @param level The level in which to render the model. Can be empty (i.e. {@link EmptyBlockAndTintGetter}). - * @param pos The position of the block in the level. Should be {@link BlockPos#ZERO} if the level is empty. - * - * - * @see FabricOrderedSubmitNodeCollector#submitBlock(PoseStack, BlockState, int, int, int, BlockAndTintGetter, BlockPos) - */ - default void renderSingleBlock(BlockState state, PoseStack poseStack, MultiBufferSource bufferSource, int light, int overlay, BlockAndTintGetter level, BlockPos pos) { - Renderer.get().renderSingleBlock((BlockRenderDispatcher) this, state, - poseStack, bufferSource, null, light, overlay, - level, pos); - } -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricLayerRenderState.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricLayerRenderState.java index c6f441ee1f2..e9bbce1564b 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricLayerRenderState.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricLayerRenderState.java @@ -20,9 +20,7 @@ import java.util.function.Supplier; import net.minecraft.client.renderer.item.ItemStackRenderState; -import net.minecraft.client.renderer.rendertype.RenderType; -import net.fabricmc.fabric.api.client.renderer.v1.Renderer; import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter; /** @@ -44,22 +42,6 @@ public interface FabricLayerRenderState { *

Do not retain references outside the context of this layer. */ default QuadEmitter emitter() { - return Renderer.get().getLayerRenderStateEmitter((ItemStackRenderState.LayerRenderState) this); - } - - /** - * Sets the function that chooses the {@link RenderType} for quads added to this layer through {@link #emitter()} - * based on certain quad properties. This method has no effect on how - * {@linkplain ItemStackRenderState.LayerRenderState#prepareQuadList() vanilla quads} are rendered. If this function - * is not set, all non-vanilla quads in this layer will be rendered using this layer's - * {@linkplain ItemStackRenderState.LayerRenderState#setRenderType(RenderType) default render type}. If the - * function returns {@code null} for a certain combination of quad properties, then all non-vanilla quads with - * matching property values will use this layer's default render type. This layer's function will be unset on - * {@link ItemStackRenderState.LayerRenderState#clear()}. - * - * @see ItemRenderTypeGetter - */ - default void setRenderTypeGetter(ItemRenderTypeGetter renderTypeGetter) { - Renderer.get().setLayerRenderTypeGetter((ItemStackRenderState.LayerRenderState) this, renderTypeGetter); + throw new AssertionError("Implemented in mixin."); } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricModelBlockRenderer.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricModelBlockRenderer.java deleted file mode 100644 index f399dfd6ade..00000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricModelBlockRenderer.java +++ /dev/null @@ -1,174 +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 java.util.function.Predicate; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; - -import net.minecraft.client.renderer.block.BlockRenderDispatcher; -import net.minecraft.client.renderer.block.ModelBlockRenderer; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; -import net.minecraft.core.BlockPos; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.EmptyBlockAndTintGetter; -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.QuadEmitter; - -/** - * Note: This interface is automatically implemented on {@link ModelBlockRenderer} via Mixin and interface injection. - */ -public interface FabricModelBlockRenderer { - /** - * Alternative for - * {@link ModelBlockRenderer#tesselateBlock(BlockAndTintGetter, List, BlockState, BlockPos, PoseStack, VertexConsumer, boolean, int)} - * and - * {@link BlockRenderDispatcher#renderBatched(BlockState, BlockPos, BlockAndTintGetter, PoseStack, VertexConsumer, boolean, List)} - * that accepts a {@link BlockStateModel} instead of a {@code List} and a - * {@link BlockMultiBufferSource} instead of a {@link VertexConsumer}. Also accepts the random seed. Prefer - * using this method over the vanilla alternative to correctly retrieve geometry from models that implement - * {@link BlockStateModel#emitQuads(QuadEmitter, BlockAndTintGetter, BlockPos, BlockState, RandomSource, Predicate)} - * and to correctly buffer models that have geometry on multiple {@linkplain ChunkSectionLayer chunk layers}. - * - *

This method allows buffering a block model in a terrain-like context, which usually includes stages like - * culling, dynamic tinting, shading, and flat/smooth lighting. - * - * @param level The level in which to render the model. Should not be empty (i.e. not - * {@link EmptyBlockAndTintGetter}). - * @param model The model to render. - * @param state The block state. - * @param pos The position of the block in the level. - * @param poseStack The pose stack. - * @param bufferSource The buffer source. - * @param layerFilter Specifies the chunk layers for which geometry should be buffered ({@code true}) or discarded - * ({@code false}). - * @param cull Whether to try to cull faces hidden by other blocks. - * @param seed The random seed. Usually retrieved by the caller from {@link BlockState#getSeed(BlockPos)}. - * @param overlay The overlay value to pass to output {@link VertexConsumer}s. - */ - default void tesselateBlock(BlockAndTintGetter level, BlockStateModel model, BlockState state, BlockPos pos, PoseStack poseStack, BlockMultiBufferSource bufferSource, Predicate layerFilter, boolean cull, long seed, int overlay) { - Renderer.get().tesselateBlock((ModelBlockRenderer) this, - level, model, state, pos, poseStack, - bufferSource, layerFilter, cull, seed, overlay); - } - - /** - * Alternative for - * {@link ModelBlockRenderer#tesselateBlock(BlockAndTintGetter, List, BlockState, BlockPos, PoseStack, VertexConsumer, boolean, int)} - * and - * {@link BlockRenderDispatcher#renderBatched(BlockState, BlockPos, BlockAndTintGetter, PoseStack, VertexConsumer, boolean, List)} - * that accepts a {@link BlockStateModel} instead of a {@code List} and a - * {@link BlockMultiBufferSource} instead of a {@link VertexConsumer}. Also accepts the random seed. Prefer - * using this method over the vanilla alternative to correctly retrieve geometry from models that implement - * {@link BlockStateModel#emitQuads(QuadEmitter, BlockAndTintGetter, BlockPos, BlockState, RandomSource, Predicate)} - * and to correctly buffer models that have geometry on multiple {@linkplain ChunkSectionLayer chunk layers}. - * - *

This method allows buffering a block model in a terrain-like context, which usually includes stages like - * culling, dynamic tinting, shading, and flat/smooth lighting. - * - * @param level The level in which to render the model. Should not be empty (i.e. not - * {@link EmptyBlockAndTintGetter}). - * @param model The model to render. - * @param state The block state. - * @param pos The position of the block in the level. - * @param poseStack The pose stack. - * @param bufferSource The buffer source. - * @param cull Whether to try to cull faces hidden by other blocks. - * @param seed The random seed. Usually retrieved by the caller from {@link BlockState#getSeed(BlockPos)}. - * @param overlay The overlay value to pass to output {@link VertexConsumer}s. - */ - default void tesselateBlock(BlockAndTintGetter level, BlockStateModel model, BlockState state, BlockPos pos, PoseStack poseStack, BlockMultiBufferSource bufferSource, boolean cull, long seed, int overlay) { - Renderer.get().tesselateBlock((ModelBlockRenderer) this, - level, model, state, pos, poseStack, - bufferSource, null, cull, seed, overlay); - } - - /** - * Alternative for - * {@link ModelBlockRenderer#renderModel(PoseStack.Pose, VertexConsumer, BlockStateModel, float, float, float, int, int)} - * that accepts a {@link BlockMultiBufferSource} instead of a {@link VertexConsumer}. Also accepts the - * {@link BlockAndTintGetter}, {@link BlockPos}, and {@link BlockState} to pass to - * {@link BlockStateModel#emitQuads(QuadEmitter, BlockAndTintGetter, BlockPos, BlockState, RandomSource, Predicate)} - * when necessary. Prefer using this method over the vanilla alternative to correctly buffer models that have - * geometry on multiple chunk layers and to provide the model with additional context. - * - *

This method allows buffering a block model with minimal transformations to the model geometry. Usually used by - * entity renderers. - * - * @param pose The pose. - * @param bufferSource The buffer source. - * @param layerFilter Specifies the chunk layers for which geometry should be buffered ({@code true}) or discarded - * ({@code false}). - * @param model The model to render. - * @param red The red component of the tint color. - * @param green The green component of the tint color. - * @param blue The blue component of the tint color. - * @param light The minimum light value. - * @param overlay The overlay value. - * @param level The level in which to render the model. Can be empty (i.e. {@link EmptyBlockAndTintGetter}). - * @param pos The position of the block in the level. Should be {@link BlockPos#ZERO} if the level is empty. - * - * @param state The block state. Should be {@code Blocks.AIR.getDefaultState()} if not applicable. - * - * @see FabricOrderedSubmitNodeCollector#submitBlockModel(PoseStack, Function, BlockStateModel, float, float, float, int, int, int, BlockAndTintGetter, BlockPos, BlockState) - */ - static void renderModel(PoseStack.Pose pose, BlockMultiBufferSource bufferSource, Predicate layerFilter, BlockStateModel model, float red, float green, float blue, int light, int overlay, BlockAndTintGetter level, BlockPos pos, BlockState state) { - Renderer.get().renderModel( - pose, bufferSource, layerFilter, model, red, green, - blue, light, overlay, level, pos, state); - } - - /** - * Alternative for - * {@link ModelBlockRenderer#renderModel(PoseStack.Pose, VertexConsumer, BlockStateModel, float, float, float, int, int)} - * that accepts a {@link BlockMultiBufferSource} instead of a {@link VertexConsumer}. Also accepts the - * {@link BlockAndTintGetter}, {@link BlockPos}, and {@link BlockState} to pass to - * {@link BlockStateModel#emitQuads(QuadEmitter, BlockAndTintGetter, BlockPos, BlockState, RandomSource, Predicate)} - * when necessary. Prefer using this method over the vanilla alternative to correctly buffer models that have - * geometry on multiple chunk layers and to provide the model with additional context. - * - *

This method allows buffering a block model with minimal transformations to the model geometry. Usually used by - * entity renderers. - * - * @param pose The pose. - * @param bufferSource The buffer source. - * @param model The model to render. - * @param red The red component of the tint color. - * @param green The green component of the tint color. - * @param blue The blue component of the tint color. - * @param light The minimum light value. - * @param overlay The overlay value. - * @param level The level in which to render the model. Can be empty (i.e. {@link EmptyBlockAndTintGetter}). - * @param pos The position of the block in the level. Should be {@link BlockPos#ZERO} if the level is empty. - * - * @param state The block state. Should be {@code Blocks.AIR.getDefaultState()} if not applicable. - * - * @see FabricOrderedSubmitNodeCollector#submitBlockModel(PoseStack, Function, BlockStateModel, float, float, float, int, int, int, BlockAndTintGetter, BlockPos, BlockState) - */ - static void renderModel(PoseStack.Pose pose, BlockMultiBufferSource bufferSource, BlockStateModel model, float red, float green, float blue, int light, int overlay, BlockAndTintGetter level, BlockPos pos, BlockState state) { - Renderer.get().renderModel( - pose, bufferSource, null, model, red, green, - blue, light, overlay, level, pos, state); - } -} 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 5f344ef5a79..6df8f70bfea 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 @@ -16,88 +16,57 @@ package net.fabricmc.fabric.api.client.renderer.v1.render; -import java.util.function.Function; -import java.util.function.Predicate; +import java.util.List; import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.client.renderer.ItemBlockRenderTypes; -import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.OrderedSubmitNodeCollector; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; +import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart; +import net.minecraft.client.renderer.item.ItemStackRenderState; import net.minecraft.client.renderer.rendertype.RenderType; -import net.minecraft.client.renderer.special.SpecialModelRenderer; -import net.minecraft.core.BlockPos; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.EmptyBlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.world.item.ItemDisplayContext; -import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter; +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 OrderedSubmitNodeCollector} via Mixin and interface injection. */ public interface FabricOrderedSubmitNodeCollector { + // TODO FRAPI 26.1 + // reintroduce Function renderTypeFunction? + // should this be MeshView instead of Mesh? /** - * Alternative for - * {@link OrderedSubmitNodeCollector#submitBlock(PoseStack, BlockState, int, int, int)} that additionally accepts the - * {@link BlockAndTintGetter} and {@link BlockPos} to pass to - * {@link BlockStateModel#emitQuads(QuadEmitter, BlockAndTintGetter, BlockPos, BlockState, RandomSource, Predicate)} when - * necessary. Prefer using this method over the vanilla alternative to correctly render models that have geometry - * on multiple {@linkplain ChunkSectionLayer chunk layers} and to provide the model with additional context. + * Alternative to {@link OrderedSubmitNodeCollector#submitBlockModel(PoseStack, RenderType, List, int[], int, int, int)} that also accepts a {@link Mesh}. * - *

This method allows rendering a block model with minimal transformations to the model geometry. Also invokes - * the {@link SpecialModelRenderer}. Usually used by entity renderers. - * - * @param poseStack The pose stack. - * @param state The block state. - * @param light The minimum light value. - * @param overlay The overlay value. - * @param outlineColor The outline color. - * @param level The level in which to render the model. Can be empty (i.e. {@link EmptyBlockAndTintGetter}). - * Must not be mutated after calling this method. - * @param pos The position of the block in the level. Should be {@link BlockPos#ZERO} if the level is empty. - * Must not be mutated after calling this method. - * - * @see FabricBlockRenderDispatcher#renderSingleBlock(BlockState, PoseStack, MultiBufferSource, int, int, BlockAndTintGetter, BlockPos) + * @param poseStack the pose stack + * @param renderType the render type + * @param parts the vanilla {@linkplain BlockStateModelPart parts} + * @param mesh the mesh + * @param tintLayers the array of tint layers + * @param lightCoords the light coordinates + * @param overlayCoords the overlay coordinates + * @param outlineColor the block outline color */ - default void submitBlock(PoseStack poseStack, BlockState state, int light, int overlay, int outlineColor, BlockAndTintGetter level, BlockPos pos) { - ((OrderedSubmitNodeCollector) this).submitBlock(poseStack, state, light, overlay, outlineColor); + default void submitBlockModel(PoseStack poseStack, RenderType renderType, List parts, Mesh mesh, int[] tintLayers, int lightCoords, int overlayCoords, int outlineColor) { + ((OrderedSubmitNodeCollector) this).submitBlockModel(poseStack, renderType, parts, tintLayers, lightCoords, overlayCoords, outlineColor); } /** - * Alternative for - * {@link OrderedSubmitNodeCollector#submitBlockModel(PoseStack, RenderType, BlockStateModel, float, float, float, int, int, int)} - * that accepts a {@code Function} instead of a {@link RenderType}. Also accepts the - * {@link BlockAndTintGetter}, {@link BlockPos}, and {@link BlockState} to pass to - * {@link BlockStateModel#emitQuads(QuadEmitter, BlockAndTintGetter, BlockPos, BlockState, RandomSource, Predicate)} when - * necessary. Prefer using this method over the vanilla alternative to correctly render models that have geometry - * on multiple {@linkplain ChunkSectionLayer chunk layers} and to provide the model with additional context. - * - *

This method allows rendering a block model with minimal transformations to the model geometry. Usually used by - * entity renderers. - * - * @param poseStack The pose stack. - * @param renderTypeFunction The function to use to convert {@link ChunkSectionLayer}s to {@link RenderType}s. - * Must not be mutated after calling this method. - * @param model The model to render. - * @param r The red component of the tint color. - * @param g The green component of the tint color. - * @param b The blue component of the tint color. - * @param light The minimum light value. - * @param overlay The overlay value. - * @param outlineColor The outline color. - * @param level The level in which to render the model. Can be empty (i.e. {@link EmptyBlockAndTintGetter}). - * Must not be mutated after calling this method. - * @param pos The position of the block in the level. Should be {@link BlockPos#ZERO} if the level is empty. - * Must not be mutated after calling this method. - * @param state The block state. Should be {@code Blocks.AIR.getDefaultState()} if not applicable. + * Alternative to {@link OrderedSubmitNodeCollector#submitItem(PoseStack, ItemDisplayContext, int, int, int, int[], List, ItemStackRenderState.FoilType)} that also accepts a {@link MeshView}. * - * @see FabricModelBlockRenderer#renderModel(PoseStack.Pose, BlockMultiBufferSource, BlockStateModel, float, float, float, int, int, BlockAndTintGetter, BlockPos, BlockState) + * @param poseStack the pose stack + * @param displayContext the item display context + * @param lightCoords the light coordinates + * @param overlayCoords the overlay coordinates + * @param outlineColor the block outline color + * @param tintLayers the array of tint layers + * @param quads the list of vanilla quads + * @param mesh the mesh + * @param foilType the foil type */ - default void submitBlockModel(PoseStack poseStack, Function renderTypeFunction, BlockStateModel model, float r, float g, float b, int light, int overlay, int outlineColor, BlockAndTintGetter level, BlockPos pos, BlockState state) { - ((OrderedSubmitNodeCollector) this).submitBlockModel(poseStack, renderTypeFunction.apply(ItemBlockRenderTypes.getChunkRenderType(state)), model, r, g, b, light, overlay, outlineColor); + default void submitItem(PoseStack poseStack, ItemDisplayContext displayContext, int lightCoords, int overlayCoords, int outlineColor, int[] tintLayers, List quads, MeshView mesh, ItemStackRenderState.FoilType foilType) { + ((OrderedSubmitNodeCollector) this).submitItem(poseStack, displayContext, lightCoords, overlayCoords, outlineColor, tintLayers, quads, foilType); } } 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 new file mode 100644 index 00000000000..bcf71f53958 --- /dev/null +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/FabricSubmitNodeCollection.java @@ -0,0 +1,69 @@ +/* + * 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 com.mojang.blaze3d.vertex.PoseStack; + +import net.minecraft.client.renderer.SubmitNodeCollection; +import net.minecraft.client.renderer.SubmitNodeStorage.BlockModelSubmit; +import net.minecraft.client.renderer.SubmitNodeStorage.ItemSubmit; +import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart; +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 BlockModelSubmit} that accepts a {@link Mesh}. + */ + record ExtendedBlockModelSubmit(PoseStack.Pose pose, RenderType renderType, List modelParts, Mesh mesh, int[] tintLayers, int lightCoords, int overlayCoords, int outlineColor) { + } + + /** + * An alternative to {@link ItemSubmit} 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/ItemRenderTypeGetter.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/ItemRenderTypeGetter.java deleted file mode 100644 index f7ec1598a80..00000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/render/ItemRenderTypeGetter.java +++ /dev/null @@ -1,38 +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 org.jspecify.annotations.Nullable; - -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; -import net.minecraft.client.renderer.item.ItemStackRenderState; -import net.minecraft.client.renderer.rendertype.RenderType; - -import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadAtlas; - -@FunctionalInterface -public interface ItemRenderTypeGetter { - /** - * Gets the {@link RenderType} for the given {@link QuadAtlas} and nullable {@link ChunkSectionLayer}. Quads with - * matching property values will be rendered using the returned render type. - * - *

A return value of {@code null} means that the current item layer's - * {@linkplain ItemStackRenderState.LayerRenderState#setRenderType(RenderType) default render type} will be used. - */ - @Nullable - RenderType renderType(QuadAtlas quadAtlas, @Nullable ChunkSectionLayer sectionLayer); -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/sprite/FabricSpriteGetter.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/sprite/FabricMaterialBaker.java similarity index 69% rename from fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/sprite/FabricSpriteGetter.java rename to fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/sprite/FabricMaterialBaker.java index 6ef67c56271..994f39a5cbb 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/sprite/FabricSpriteGetter.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/sprite/FabricMaterialBaker.java @@ -16,24 +16,24 @@ package net.fabricmc.fabric.api.client.renderer.v1.sprite; -import net.minecraft.client.resources.model.SpriteGetter; +import net.minecraft.client.resources.model.sprite.MaterialBaker; import net.minecraft.resources.Identifier; import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadAtlas; /** - * Note: This interface is automatically implemented on {@link SpriteGetter} via Mixin and interface injection. + * Note: This interface is automatically implemented on {@link MaterialBaker} via Mixin and interface injection. */ -public interface FabricSpriteGetter extends SpriteFinderGetter { +public interface FabricMaterialBaker extends SpriteFinderGetter { /** - * {@return the sprite finder for the given atlas texture ID} + * {@return the sprite finder for the given atlas ID} */ - default SpriteFinder spriteFinder(Identifier atlasTextureId) { + default SpriteFinder spriteFinder(Identifier atlasId) { throw new UnsupportedOperationException(); } @Override default SpriteFinder spriteFinder(QuadAtlas quadAtlas) { - return spriteFinder(quadAtlas.getTextureId()); + return spriteFinder(quadAtlas.getId()); } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/sprite/FabricTextureAtlas.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/sprite/FabricTextureAtlas.java index f7065bd6202..68371847d5f 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/sprite/FabricTextureAtlas.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/sprite/FabricTextureAtlas.java @@ -31,7 +31,7 @@ public interface FabricTextureAtlas { * *

This method should not be used during a resource reload as this atlas will only be populated with new * sprites towards the end of the resource reload. In this case, use - * {@link FabricSpriteGetter#spriteFinder(Identifier)} or {@link FabricPreparations#spriteFinder()} + * {@link FabricMaterialBaker#spriteFinder(Identifier)} or {@link FabricPreparations#spriteFinder()} * instead. * * @return the sprite finder for this atlas diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/sprite/SpriteFinder.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/sprite/SpriteFinder.java index 4230228046c..5e8dd994ad2 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/sprite/SpriteFinder.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/sprite/SpriteFinder.java @@ -20,12 +20,13 @@ import org.jetbrains.annotations.ApiStatus; +import net.minecraft.client.renderer.block.BlockAndTintGetter; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.SpriteGetter; +import net.minecraft.client.resources.model.sprite.Material; +import net.minecraft.client.resources.model.sprite.SpriteGetter; import net.minecraft.core.BlockPos; import net.minecraft.resources.Identifier; import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; import net.fabricmc.fabric.api.client.renderer.v1.mesh.MutableQuadView; @@ -41,7 +42,7 @@ * finding the sprite for use in {@link QuadView#toBakedQuad(TextureAtlasSprite)}. * *

A sprite finder can be retrieved from various vanilla objects. Always use - * {@link FabricSpriteGetter#spriteFinder(Identifier)} or {@link FabricPreparations#spriteFinder()} + * {@link FabricMaterialBaker#spriteFinder(Identifier)} or {@link FabricPreparations#spriteFinder()} * whenever an applicable instance is available. For example, model baking is supplied with a * {@link SpriteGetter}, so it should be used to retrieve the sprite finder. In most other cases, it is * safe to use {@link FabricTextureAtlas#spriteFinder()}. @@ -63,7 +64,7 @@ public interface SpriteFinder { * Alternative to {@link #find(QuadView)} when vertex centroid is already * known or unsuitable. Expects normalized (0-1) coordinates on the atlas texture, * which should already be the case for u,v values in vanilla baked quads and in - * {@link QuadView} after calling {@link MutableQuadView#spriteBake(TextureAtlasSprite, int)}. + * {@link QuadView} after calling {@link MutableQuadView#materialBake(Material.Baked, int)}. * *

Coordinates must be in the sprite interior for reliable results. Generally will * be easier to use {@link #find(QuadView)} unless you know the vertex diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/BlockModelWrapperExtension.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/BlockModelWrapperExtension.java deleted file mode 100644 index 5a357cbecb0..00000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/BlockModelWrapperExtension.java +++ /dev/null @@ -1,25 +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 net.minecraft.client.resources.model.SpriteGetter; - -import net.fabricmc.fabric.api.client.renderer.v1.mesh.Mesh; - -public interface BlockModelWrapperExtension { - void fabric_setMesh(Mesh mesh, SpriteGetter spriteGetter); -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/DelegatingBlockMultiBufferSourceImpl.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/DelegatingBlockMultiBufferSourceImpl.java deleted file mode 100644 index 2088ac5c30c..00000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/DelegatingBlockMultiBufferSourceImpl.java +++ /dev/null @@ -1,49 +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.Function; -import java.util.function.Predicate; - -import com.mojang.blaze3d.vertex.VertexConsumer; - -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; -import net.minecraft.client.renderer.rendertype.RenderType; - -import net.fabricmc.fabric.api.client.renderer.v1.render.BlockMultiBufferSource; - -public class DelegatingBlockMultiBufferSourceImpl implements BlockMultiBufferSource, Predicate { - public final boolean translucent; - - public MultiBufferSource multiBufferSource; - public Function renderTypeFunction; - - public DelegatingBlockMultiBufferSourceImpl(boolean translucent) { - this.translucent = translucent; - } - - @Override - public VertexConsumer getBuffer(ChunkSectionLayer layer) { - return multiBufferSource.getBuffer(renderTypeFunction.apply(layer)); - } - - @Override - public boolean test(ChunkSectionLayer layer) { - return renderTypeFunction.apply(layer).hasBlending() == translucent; - } -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/ExtendedBlockModelSubmit.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/ExtendedBlockModelSubmit.java deleted file mode 100644 index 919e00100e2..00000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/ExtendedBlockModelSubmit.java +++ /dev/null @@ -1,31 +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.Function; - -import com.mojang.blaze3d.vertex.PoseStack; - -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; -import net.minecraft.client.renderer.rendertype.RenderType; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; - -public record ExtendedBlockModelSubmit(PoseStack.Pose pose, Function renderTypeFunction, BlockStateModel model, float r, float g, float b, int lightCoords, int overlayCoords, int outlineColor, BlockAndTintGetter level, BlockPos pos, BlockState state) { -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/ExtendedBlockSubmit.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/ExtendedBlockSubmit.java deleted file mode 100644 index ba8578645e4..00000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/ExtendedBlockSubmit.java +++ /dev/null @@ -1,26 +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.PoseStack; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; - -public record ExtendedBlockSubmit(PoseStack.Pose pose, BlockState state, int lightCoords, int overlayCoords, int outlineColor, BlockAndTintGetter level, BlockPos pos) { -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/SubmitNodeCollectionExtension.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/LayerRenderStateExtension.java similarity index 76% rename from fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/SubmitNodeCollectionExtension.java rename to fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/LayerRenderStateExtension.java index 009309f8faf..60d97e145e1 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/SubmitNodeCollectionExtension.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/LayerRenderStateExtension.java @@ -16,10 +16,11 @@ package net.fabricmc.fabric.impl.client.renderer; -import java.util.List; +import org.jspecify.annotations.Nullable; -public interface SubmitNodeCollectionExtension { - List fabric_getExtendedBlockSubmits(); +import net.fabricmc.fabric.api.client.renderer.v1.mesh.MutableMesh; - List fabric_getExtendedBlockModelSubmits(); +public interface LayerRenderStateExtension { + @Nullable + MutableMesh fabric_getMutableMesh(); } 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 new file mode 100644 index 00000000000..827b782bf4a --- /dev/null +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/QuadConsumers.java @@ -0,0 +1,77 @@ +/* + * 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 com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import org.jspecify.annotations.Nullable; + +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 VertexConsumer buffer; + @Nullable + public VertexConsumer outlineBuffer; + + @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]); + } + + quad.buffer(overlayCoords, pose, buffer); + + 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-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/QuadToPosPipe.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/QuadToPosPipe.java similarity index 95% rename from fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/QuadToPosPipe.java rename to fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/QuadToPosPipe.java index 8f5e5ad224d..23798cc3d9a 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/QuadToPosPipe.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/QuadToPosPipe.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.impl.client.indigo.renderer.render; +package net.fabricmc.fabric.impl.client.renderer; import java.util.function.Consumer; diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/VanillaBlockModelPartEncoder.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/VanillaBlockModelPartEncoder.java index 8140de963ca..21773a572b2 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/VanillaBlockModelPartEncoder.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/VanillaBlockModelPartEncoder.java @@ -21,8 +21,8 @@ import org.jspecify.annotations.Nullable; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.block.model.BlockModelPart; +import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart; +import net.minecraft.client.resources.model.geometry.BakedQuad; import net.minecraft.core.Direction; import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter; @@ -31,10 +31,10 @@ import net.fabricmc.fabric.api.util.TriState; /** - * Routines for adaptation of vanilla {@link BlockModelPart}s to FRAPI pipelines. + * Routines for adaptation of vanilla {@link BlockStateModelPart}s to FRAPI pipelines. */ public class VanillaBlockModelPartEncoder { - public static void emitQuads(BlockModelPart part, QuadEmitter emitter, Predicate<@Nullable Direction> cullTest) { + public static void emitQuads(BlockStateModelPart part, QuadEmitter emitter, Predicate<@Nullable Direction> cullTest) { // This does not exactly match vanilla, but doing so requires hiding state all over the FRAPI impl. final TriState ao = part.useAmbientOcclusion() ? TriState.DEFAULT : TriState.FALSE; diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/BlockStateModelMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/BlockStateModelMixin.java index 185bd490169..dab60ff6613 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/BlockStateModelMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/BlockStateModelMixin.java @@ -18,7 +18,7 @@ import org.spongepowered.asm.mixin.Mixin; -import net.minecraft.client.renderer.block.model.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; import net.fabricmc.fabric.api.client.renderer.v1.model.FabricBlockStateModel; diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/BlockModelPartMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/BlockStateModelPartMixin.java similarity index 80% rename from fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/BlockModelPartMixin.java rename to fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/BlockStateModelPartMixin.java index 1efba64bf00..a4decfb26fe 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/BlockModelPartMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/BlockStateModelPartMixin.java @@ -18,10 +18,10 @@ import org.spongepowered.asm.mixin.Mixin; -import net.minecraft.client.renderer.block.model.BlockModelPart; +import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart; -import net.fabricmc.fabric.api.client.renderer.v1.model.FabricBlockModelPart; +import net.fabricmc.fabric.api.client.renderer.v1.model.FabricBlockStateModelPart; -@Mixin(BlockModelPart.class) -interface BlockModelPartMixin extends FabricBlockModelPart { +@Mixin(BlockStateModelPart.class) +interface BlockStateModelPartMixin extends FabricBlockStateModelPart { } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/MultiPartModelMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/MultiPartModelMixin.java index 02a2868a224..99e2a3ba882 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/MultiPartModelMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/MultiPartModelMixin.java @@ -25,13 +25,13 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.block.model.multipart.MultiPartModel; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.multipart.MultiPartModel; +import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter; @@ -101,8 +101,8 @@ record Key(List subkeys) { } @Override - public TextureAtlasSprite particleIcon(BlockAndTintGetter level, BlockPos pos, BlockState state) { - return ((MultiPartModelSharedBakedStateAccessor) (Object) shared).getSelectors().getFirst().model().particleIcon( + public Material.Baked particleMaterial(BlockAndTintGetter level, BlockPos pos, BlockState state) { + return ((MultiPartModelSharedBakedStateAccessor) (Object) shared).getSelectors().getFirst().model().particleMaterial( level, pos, state); } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/MultiPartModelSharedBakedStateAccessor.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/MultiPartModelSharedBakedStateAccessor.java index 4159b7a5128..64b0ecf2f57 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/MultiPartModelSharedBakedStateAccessor.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/MultiPartModelSharedBakedStateAccessor.java @@ -21,8 +21,8 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.block.model.multipart.MultiPartModel; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.multipart.MultiPartModel; @Mixin(MultiPartModel.SharedBakedState.class) public interface MultiPartModelSharedBakedStateAccessor { 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 63729feec8d..567d9638a0f 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 @@ -30,12 +30,12 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import net.minecraft.client.renderer.block.model.BlockModelPart; -import net.minecraft.client.renderer.block.model.SimpleModelWrapper; +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.ModelState; -import net.minecraft.client.resources.model.QuadCollection; +import net.minecraft.client.resources.model.SimpleModelWrapper; +import net.minecraft.client.resources.model.geometry.QuadCollection; import net.minecraft.core.Direction; import net.minecraft.resources.Identifier; @@ -45,7 +45,7 @@ import net.fabricmc.fabric.api.util.TriState; @Mixin(SimpleModelWrapper.class) -abstract class SimpleModelWrapperMixin implements BlockModelPart { +abstract class SimpleModelWrapperMixin implements BlockStateModelPart { @Shadow @Final private QuadCollection quads; @@ -53,10 +53,10 @@ abstract class SimpleModelWrapperMixin implements BlockModelPart { @Final private boolean useAmbientOcclusion; - @Inject(method = "bake(Lnet/minecraft/client/resources/model/ModelBaker;Lnet/minecraft/resources/Identifier;Lnet/minecraft/client/resources/model/ModelState;)Lnet/minecraft/client/renderer/block/model/BlockModelPart;", at = @At(value = "INVOKE", target = "net/minecraft/client/resources/model/QuadCollection.getAll()Ljava/util/List;")) - private static void validateMeshAtlas(final ModelBaker modelBakery, final Identifier location, final ModelState state, CallbackInfoReturnable cir, @Local(name = "geometry") QuadCollection geometry, @Local(name = "forbiddenSprites") LocalRef> forbiddenSpritesRef) { - if (geometry instanceof MeshQuadCollection meshGeometry) { - meshGeometry.getMesh().forEach(quad -> { + @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) { + if (geometry instanceof MeshQuadCollection meshQuadCollection) { + meshQuadCollection.getMesh().forEach(quad -> { if (quad.atlas() != QuadAtlas.BLOCK) { Multimap forbiddenSprites = forbiddenSpritesRef.get(); @@ -65,7 +65,7 @@ private static void validateMeshAtlas(final ModelBaker modelBakery, final Identi forbiddenSpritesRef.set(forbiddenSprites); } - TextureAtlasSprite sprite = modelBakery.sprites().spriteFinder(quad.atlas()).find(quad); + TextureAtlasSprite sprite = modelBakery.materials().spriteFinder(quad.atlas()).find(quad); forbiddenSprites.put(sprite.atlasLocation(), sprite.contents().name()); } }); @@ -89,7 +89,7 @@ public void emitQuads(QuadEmitter emitter, Predicate<@Nullable Direction> cullTe emitter.popTransform(); } } else { - BlockModelPart.super.emitQuads(emitter, cullTest); + BlockStateModelPart.super.emitQuads(emitter, cullTest); } } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/SingleVariantMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/SingleVariantMixin.java index 15e94cf7892..de5febe8550 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/SingleVariantMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/SingleVariantMixin.java @@ -23,13 +23,16 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import net.minecraft.client.renderer.block.model.BlockModelPart; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.block.model.SingleVariant; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.ModelBlockRenderer; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart; +import net.minecraft.client.renderer.block.dispatch.SingleVariant; +import net.minecraft.client.renderer.chunk.ChunkSectionLayer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter; @@ -38,13 +41,27 @@ abstract class SingleVariantMixin implements BlockStateModel { @Shadow @Final - private BlockModelPart model; + private BlockStateModelPart model; // Not strictly necessary for FRAPI compatibility like other mixins, but saves a list allocation and some other // operations over this method's default impl. @Override public void emitQuads(QuadEmitter emitter, BlockAndTintGetter level, BlockPos pos, BlockState state, RandomSource random, Predicate<@Nullable Direction> cullTest) { + final boolean cutoutLeaves = Minecraft.getInstance().options.cutoutLeaves().get(); + final boolean forceOpaque = ModelBlockRenderer.forceOpaque(cutoutLeaves, state); + + if (forceOpaque) { + emitter.pushTransform(quad -> { + quad.chunkLayer(ChunkSectionLayer.SOLID); + return true; + }); + } + model.emitQuads(emitter, cullTest); + + if (forceOpaque) { + emitter.popTransform(); + } } @Override diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/WeightedVariantsMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/WeightedVariantsMixin.java index 670fc051369..9c3693e49a3 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/WeightedVariantsMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/model/WeightedVariantsMixin.java @@ -23,14 +23,14 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.WeightedVariants; +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.WeightedVariants; +import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.RandomSource; import net.minecraft.util.random.WeightedList; -import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter; @@ -55,8 +55,8 @@ public Object createGeometryKey(BlockAndTintGetter level, BlockPos pos, BlockSta } @Override - public TextureAtlasSprite particleIcon(BlockAndTintGetter level, BlockPos pos, BlockState state) { - return list.unwrap().getFirst().value().particleIcon( + public Material.Baked particleMaterial(BlockAndTintGetter level, BlockPos pos, BlockState state) { + return list.unwrap().getFirst().value().particleMaterial( level, pos, state); } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/BlockMarkerMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/BlockMarkerMixin.java index 219cfc0f52e..732b39826b0 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/BlockMarkerMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/BlockMarkerMixin.java @@ -22,15 +22,15 @@ import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.particle.BlockMarker; -import net.minecraft.client.renderer.block.BlockModelShaper; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.block.BlockStateModelSet; +import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.state.BlockState; @Mixin(BlockMarker.class) abstract class BlockMarkerMixin { - @Redirect(method = "(Lnet/minecraft/client/multiplayer/ClientLevel;DDDLnet/minecraft/world/level/block/state/BlockState;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/block/BlockModelShaper;getParticleIcon(Lnet/minecraft/world/level/block/state/BlockState;)Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;")) - private static TextureAtlasSprite getParticleIconProxy(BlockModelShaper models, BlockState state, ClientLevel level, double x, double y, double z, BlockState state1) { - return models.getParticleIcon(state, level, BlockPos.containing(x, y, z)); + @Redirect(method = "(Lnet/minecraft/client/multiplayer/ClientLevel;DDDLnet/minecraft/world/level/block/state/BlockState;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/block/BlockStateModelSet;getParticleMaterial(Lnet/minecraft/world/level/block/state/BlockState;)Lnet/minecraft/client/resources/model/sprite/Material$Baked;")) + private static Material.Baked getParticleMaterialProxy(BlockStateModelSet models, BlockState state, ClientLevel level, double x, double y, double z, BlockState state1) { + return models.getParticleMaterial(state, level, BlockPos.containing(x, y, z)); } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/BlockModelShaperMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/BlockStateModelSetMixin.java similarity index 80% rename from fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/BlockModelShaperMixin.java rename to fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/BlockStateModelSetMixin.java index 1d06bb224f8..12a3969c3d9 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/BlockModelShaperMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/BlockStateModelSetMixin.java @@ -18,10 +18,10 @@ import org.spongepowered.asm.mixin.Mixin; -import net.minecraft.client.renderer.block.BlockModelShaper; +import net.minecraft.client.renderer.block.BlockStateModelSet; -import net.fabricmc.fabric.api.client.renderer.v1.model.FabricBlockModelShaper; +import net.fabricmc.fabric.api.client.renderer.v1.model.FabricBlockStateModelSet; -@Mixin(BlockModelShaper.class) -abstract class BlockModelShaperMixin implements FabricBlockModelShaper { +@Mixin(BlockStateModelSet.class) +abstract class BlockStateModelSetMixin implements FabricBlockStateModelSet { } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/ScreenEffectRendererMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/ScreenEffectRendererMixin.java index 52e343b79c5..c56612e76c1 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/ScreenEffectRendererMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/ScreenEffectRendererMixin.java @@ -16,18 +16,20 @@ package net.fabricmc.fabric.mixin.client.renderer.block.particle; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import com.llamalad7.mixinextras.sugar.Local; import org.jspecify.annotations.Nullable; 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.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import net.minecraft.client.renderer.ScreenEffectRenderer; -import net.minecraft.client.renderer.block.BlockModelShaper; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.BlockStateModelSet; +import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.state.BlockState; @@ -38,15 +40,15 @@ abstract class ScreenEffectRendererMixin { @Nullable private static BlockPos pos; - @Redirect(method = "renderScreenEffect", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/block/BlockModelShaper;getParticleIcon(Lnet/minecraft/world/level/block/state/BlockState;)Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;")) - private static TextureAtlasSprite getParticleIconProxy(BlockModelShaper models, BlockState state, @Local(name = "player") Player player) { - if (pos != null) { - TextureAtlasSprite sprite = models.getParticleIcon(state, player.level(), pos); + @WrapOperation(method = "renderScreenEffect", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/block/BlockStateModelSet;getParticleMaterial(Lnet/minecraft/world/level/block/state/BlockState;)Lnet/minecraft/client/resources/model/sprite/Material$Baked;")) + private static Material.Baked getParticleMaterialProxy(BlockStateModelSet models, BlockState state, Operation original, @Local(name = "player") Player player) { + if (pos != null && player.level() instanceof BlockAndTintGetter level) { + Material.Baked material = models.getParticleMaterial(state, level, pos); pos = null; - return sprite; + return material; } - return models.getParticleIcon(state); + return original.call(models, state); } @Inject(method = "getViewBlockingState", at = @At("RETURN")) diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/TerrainParticleMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/TerrainParticleMixin.java index b12225e2c8f..41f6176fbe8 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/TerrainParticleMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/particle/TerrainParticleMixin.java @@ -16,21 +16,22 @@ package net.fabricmc.fabric.mixin.client.renderer.block.particle; +import com.llamalad7.mixinextras.sugar.Local; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.particle.TerrainParticle; -import net.minecraft.client.renderer.block.BlockModelShaper; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.block.BlockStateModelSet; +import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.state.BlockState; @Mixin(TerrainParticle.class) abstract class TerrainParticleMixin { - @Redirect(method = "(Lnet/minecraft/client/multiplayer/ClientLevel;DDDDDDLnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/block/BlockModelShaper;getParticleIcon(Lnet/minecraft/world/level/block/state/BlockState;)Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;")) - private static TextureAtlasSprite getParticleIconProxy(BlockModelShaper models, BlockState state, ClientLevel level, double x, double y, double z, double velocityX, double velocityY, double velocityZ, BlockState state1, BlockPos blockPos) { - return models.getParticleIcon(state, level, blockPos); + @Redirect(method = "(Lnet/minecraft/client/multiplayer/ClientLevel;DDDDDDLnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/block/BlockStateModelSet;getParticleMaterial(Lnet/minecraft/world/level/block/state/BlockState;)Lnet/minecraft/client/resources/model/sprite/Material$Baked;")) + private static Material.Baked getParticleIconProxy(BlockStateModelSet models, BlockState state, @Local(argsOnly = true) ClientLevel level, @Local(argsOnly = true) BlockPos blockPos) { + return models.getParticleMaterial(state, level, blockPos); } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/BlockFeatureRendererMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/BlockFeatureRendererMixin.java index e3dc8db7aa9..3321f013cde 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/BlockFeatureRendererMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/BlockFeatureRendererMixin.java @@ -16,120 +16,129 @@ package net.fabricmc.fabric.mixin.client.renderer.block.render; -import java.util.function.Predicate; - +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.QuadInstance; +import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator; +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.Overwrite; 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.MultiBufferSource; import net.minecraft.client.renderer.OutlineBufferSource; import net.minecraft.client.renderer.SubmitNodeCollection; import net.minecraft.client.renderer.SubmitNodeStorage; -import net.minecraft.client.renderer.block.BlockRenderDispatcher; -import net.minecraft.client.renderer.block.MovingBlockRenderState; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.BlockQuadOutput; +import net.minecraft.client.renderer.block.BlockStateModelSet; +import net.minecraft.client.renderer.block.ModelBlockRenderer; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; +import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart; import net.minecraft.client.renderer.feature.BlockFeatureRenderer; +import net.minecraft.client.renderer.rendertype.RenderType; +import net.minecraft.client.renderer.state.OptionsRenderState; import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.resources.model.ModelBakery; import net.minecraft.core.BlockPos; -import net.minecraft.world.level.EmptyBlockAndTintGetter; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; -import net.fabricmc.fabric.api.client.renderer.v1.render.BlockMultiBufferSource; +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.AltModelBlockRenderer; import net.fabricmc.fabric.api.client.renderer.v1.render.ChunkSectionLayerHelper; -import net.fabricmc.fabric.api.client.renderer.v1.render.FabricModelBlockRenderer; -import net.fabricmc.fabric.impl.client.renderer.DelegatingBlockMultiBufferSourceImpl; -import net.fabricmc.fabric.impl.client.renderer.ExtendedBlockModelSubmit; -import net.fabricmc.fabric.impl.client.renderer.ExtendedBlockSubmit; -import net.fabricmc.fabric.impl.client.renderer.SubmitNodeCollectionExtension; +import net.fabricmc.fabric.api.client.renderer.v1.render.FabricSubmitNodeCollection; +import net.fabricmc.fabric.impl.client.renderer.QuadConsumers; +// TODO FRAPI 26.1: how much of this, if any, should be moved to Indigo? @Mixin(BlockFeatureRenderer.class) abstract class BlockFeatureRendererMixin { @Shadow @Final - private PoseStack poseStack; + private QuadInstance quadInstance; + @Shadow + @Final + private RandomSource random; - // Support multi-chunk layer models (MovingBlockSubmit). - @Overwrite - private void renderMovingBlockSubmits(final SubmitNodeCollection nodeCollection, final MultiBufferSource.BufferSource bufferSource, final BlockRenderDispatcher blockRenderDispatcher, final boolean translucent) { - BlockMultiBufferSource blockBufferSource = ChunkSectionLayerHelper.movingDelegate(bufferSource); - Predicate layerFilter = translucent ? layer -> layer == ChunkSectionLayer.TRANSLUCENT : layer -> layer != ChunkSectionLayer.TRANSLUCENT; - - for (SubmitNodeStorage.MovingBlockSubmit submit : nodeCollection.getMovingBlockSubmits()) { - MovingBlockRenderState renderState = submit.movingBlockRenderState(); - BlockState blockState = renderState.blockState; - BlockStateModel model = blockRenderDispatcher.getBlockModel(blockState); - long seed = blockState.getSeed(renderState.randomSeedPos); - poseStack.pushPose(); - poseStack.mulPose(submit.pose()); - blockRenderDispatcher.getModelRenderer().tesselateBlock(renderState, model, blockState, renderState.blockPos, poseStack, blockBufferSource, layerFilter, false, seed, OverlayTexture.NO_OVERLAY); - poseStack.popPose(); - } + @Shadow + private static void putPartQuads(BlockStateModelPart part, PoseStack.Pose pose, QuadInstance quadInstance, int[] tintLayers, VertexConsumer buffer, @Nullable VertexConsumer outlineBuffer) { } - // Support multi-chunk layer models (BlockSubmit) and ExtendedBlockSubmit. - @Overwrite - private void renderBlockSubmits(final SubmitNodeCollection nodeCollection, final MultiBufferSource.BufferSource bufferSource, final BlockRenderDispatcher blockRenderDispatcher, final OutlineBufferSource outlineBufferSource, final boolean translucent) { - Predicate layerFilter = translucent ? layer -> layer == ChunkSectionLayer.TRANSLUCENT : layer -> layer != ChunkSectionLayer.TRANSLUCENT; - - for (SubmitNodeStorage.BlockSubmit submit : nodeCollection.getBlockSubmits()) { - poseStack.pushPose(); - poseStack.last().set(submit.pose()); - blockRenderDispatcher.renderSingleBlock(submit.state(), poseStack, bufferSource, layerFilter, submit.lightCoords(), submit.overlayCoords(), EmptyBlockAndTintGetter.INSTANCE, BlockPos.ZERO); - - if (submit.outlineColor() != 0) { - outlineBufferSource.setColor(submit.outlineColor()); - blockRenderDispatcher.renderSingleBlock(submit.state(), poseStack, outlineBufferSource, layerFilter, submit.lightCoords(), submit.overlayCoords(), EmptyBlockAndTintGetter.INSTANCE, BlockPos.ZERO); - } - - poseStack.popPose(); - } - - for (ExtendedBlockSubmit submit : ((SubmitNodeCollectionExtension) nodeCollection).fabric_getExtendedBlockSubmits()) { - poseStack.pushPose(); - poseStack.last().set(submit.pose()); - blockRenderDispatcher.renderSingleBlock( - submit.state(), poseStack, - bufferSource, layerFilter, submit.lightCoords(), submit.overlayCoords(), submit.level(), submit.pos()); - - if (submit.outlineColor() != 0) { - outlineBufferSource.setColor(submit.outlineColor()); - blockRenderDispatcher.renderSingleBlock( - submit.state(), poseStack, - outlineBufferSource, layerFilter, submit.lightCoords(), submit.overlayCoords(), submit.level(), submit.pos()); - } + @Inject(method = "renderMovingBlockSubmits", at = @At(value = "INVOKE", target = "net/minecraft/client/renderer/block/ModelBlockRenderer.(ZZLnet/minecraft/client/color/block/BlockColors;)V")) + private void beforeInitBlockRenderer(SubmitNodeCollection nodeCollection, MultiBufferSource.BufferSource bufferSource, BlockStateModelSet blockStateModelSet, OptionsRenderState optionsState, boolean translucent, CallbackInfo ci, @Local(name = "poseStack") PoseStack poseStack, @Share("altBlockRenderer") LocalRef altBlockRenderer, @Share("altQuadOutput") LocalRef altQuadOutput) { + altBlockRenderer.set(Renderer.get().altModelBlockRenderer(optionsState.ambientOcclusion, false, Minecraft.getInstance().getBlockColors())); + altQuadOutput.set(Renderer.get().quadEmitter(quad -> { + RenderType renderType = ChunkSectionLayerHelper.getMovingBlockRenderType(quad.chunkLayer()); + VertexConsumer buffer = bufferSource.getBuffer(renderType); + quad.buffer(OverlayTexture.NO_OVERLAY, poseStack.last(), buffer); + })); + } - poseStack.popPose(); - } + @Redirect(method = "renderMovingBlockSubmits", 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) { + altBlockRenderer.get().tesselateBlock(altQuadOutput.get(), x, y, z, level, pos, blockState, model, seed); } - // Support ExtendedBlockModelSubmit. @Inject(method = "renderBlockModelSubmits", at = @At("RETURN")) private void onReturnRenderBlockModelSubmits(SubmitNodeCollection nodeCollection, MultiBufferSource.BufferSource bufferSource, OutlineBufferSource outlineBufferSource, boolean translucent, CallbackInfo ci) { - DelegatingBlockMultiBufferSourceImpl blockMultiBufferSource = new DelegatingBlockMultiBufferSourceImpl(translucent); - - for (ExtendedBlockModelSubmit submit : ((SubmitNodeCollectionExtension) nodeCollection).fabric_getExtendedBlockModelSubmits()) { - blockMultiBufferSource.renderTypeFunction = submit.renderTypeFunction(); - blockMultiBufferSource.multiBufferSource = bufferSource; - FabricModelBlockRenderer.renderModel( - submit.pose(), blockMultiBufferSource, blockMultiBufferSource, submit.model(), submit.r(), submit.g(), - submit.b(), submit.lightCoords(), submit.overlayCoords(), submit.level(), submit.pos(), - submit.state()); - - if (submit.outlineColor() != 0) { - outlineBufferSource.setColor(submit.outlineColor()); - blockMultiBufferSource.multiBufferSource = outlineBufferSource; - FabricModelBlockRenderer.renderModel( - submit.pose(), blockMultiBufferSource, blockMultiBufferSource, submit.model(), submit.r(), submit.g(), - submit.b(), submit.lightCoords(), submit.overlayCoords(), submit.level(), submit.pos(), - submit.state()); + QuadConsumers.BlockModel quadConsumer = new QuadConsumers.BlockModel(); + QuadEmitter output = Renderer.get().quadEmitter(quadConsumer); + + for (FabricSubmitNodeCollection.ExtendedBlockModelSubmit submit : nodeCollection.getExtendedBlockModelSubmits()) { + if (submit.renderType().hasBlending() == translucent) { + VertexConsumer buffer = bufferSource.getBuffer(submit.renderType()); + VertexConsumer outlineBuffer; + + if (submit.outlineColor() != 0) { + outlineBufferSource.setColor(submit.outlineColor()); + outlineBuffer = outlineBufferSource.getBuffer(submit.renderType()); + } else { + outlineBuffer = null; + } + + quadInstance.setLightCoords(submit.lightCoords()); + quadInstance.setOverlayCoords(submit.overlayCoords()); + + for (BlockStateModelPart part : submit.modelParts()) { + putPartQuads(part, submit.pose(), quadInstance, submit.tintLayers(), buffer, outlineBuffer); + } + + quadConsumer.tintLayers = submit.tintLayers(); + quadConsumer.lightCoords = submit.lightCoords(); + quadConsumer.overlayCoords = submit.overlayCoords(); + quadConsumer.pose = submit.pose(); + quadConsumer.buffer = buffer; + quadConsumer.outlineBuffer = outlineBuffer; + submit.mesh().outputTo(output); } } } + + // TODO FRAPI 26.1: don't use an overwrite if possible + @Overwrite + private void renderBreakingBlockModelSubmits(final SubmitNodeCollection nodeCollection, final MultiBufferSource.BufferSource bufferSource) { + QuadConsumers.BreakingBlockModel quadConsumer = new QuadConsumers.BreakingBlockModel(); + QuadEmitter output = Renderer.get().quadEmitter(quadConsumer); + + for (SubmitNodeStorage.BreakingBlockModelSubmit submit : nodeCollection.getBreakingBlockModelSubmits()) { + VertexConsumer buffer = new SheetedDecalTextureGenerator(bufferSource.getBuffer(ModelBakery.DESTROY_TYPES.get(submit.progress())), submit.pose(), 1.0F); + quadConsumer.pose = submit.pose(); + quadConsumer.buffer = buffer; + output.clear(); + random.setSeed(submit.seed()); + // TODO FRAPI 26.1: somehow pass the level, pos, and state here when available? maybe via extended submit type? + submit.model().emitQuads(output, BlockAndTintGetter.EMPTY, BlockPos.ZERO, Blocks.AIR.defaultBlockState(), random, _ -> false); + } + } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/BlockModelRenderStateMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/BlockModelRenderStateMixin.java new file mode 100644 index 00000000000..85276e8a316 --- /dev/null +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/BlockModelRenderStateMixin.java @@ -0,0 +1,122 @@ +/* + * 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 static net.minecraft.client.renderer.block.BlockModelRenderState.EMPTY_TINTS; + +import java.util.Collections; +import java.util.List; + +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import com.mojang.blaze3d.vertex.PoseStack; +import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import org.joml.Matrix4fc; +import org.jspecify.annotations.Nullable; +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.Sheets; +import net.minecraft.client.renderer.SubmitNodeCollector; +import net.minecraft.client.renderer.block.BlockModelRenderState; +import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart; +import net.minecraft.client.renderer.rendertype.RenderType; +import net.minecraft.util.RandomSource; + +import net.fabricmc.fabric.api.client.renderer.v1.Renderer; +import net.fabricmc.fabric.api.client.renderer.v1.mesh.Mesh; +import net.fabricmc.fabric.api.client.renderer.v1.mesh.MutableMesh; +import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter; +import net.fabricmc.fabric.api.client.renderer.v1.render.FabricBlockModelRenderState; + +@Mixin(BlockModelRenderState.class) +public abstract class BlockModelRenderStateMixin implements FabricBlockModelRenderState { + @Shadow + @Nullable + private List modelParts; + @Shadow + @Nullable + private Matrix4fc transformation; + @Shadow + @Nullable + private RenderType renderType; + @Shadow + @Nullable + private IntList tintLayers; + @Shadow + @Nullable + private RandomSource randomSource; + + @Unique + @Nullable + private MutableMesh mesh; + + @Shadow + @Nullable + private static Matrix4fc identityToNull(Matrix4fc transformation) { + return null; + } + + @Override + public QuadEmitter setupMesh(Matrix4fc transformation, boolean hasTranslucency) { + this.transformation = identityToNull(transformation); + renderType = hasTranslucency ? Sheets.translucentBlockSheet() : Sheets.cutoutBlockSheet(); + + if (mesh == null) { + mesh = Renderer.get().mutableMesh(); + } else { + mesh.clear(); + } + + return mesh.emitter(); + } + + @Inject(method = "clear()V", at = @At("RETURN")) + private void onReturnClear(CallbackInfo ci) { + mesh = null; + } + + @ModifyReturnValue(method = "isEmpty()Z", at = @At("RETURN")) + private boolean modifyIsEmpty(boolean original) { + return original && mesh == null; + } + + // TODO FRAPI 26.1: improve this injection or use a second submit for just the mesh + @Inject(method = "submitModel", at = @At("HEAD"), cancellable = true) + private void submitMesh(RenderType renderType, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, int overlayCoords, int outlineColor, CallbackInfo ci) { + if (mesh != null && mesh.size() > 0) { + List modelPartsCopy = modelParts != null && !modelParts.isEmpty() ? new ObjectArrayList<>(modelParts) : Collections.emptyList(); + Mesh meshCopy = mesh.immutableCopy(); + int[] tints = tintLayers != null ? tintLayers.toArray(EMPTY_TINTS) : EMPTY_TINTS; + + if (transformation != null) { + poseStack.pushPose(); + poseStack.mulPose(transformation); + submitNodeCollector.submitBlockModel(poseStack, renderType, modelPartsCopy, meshCopy, tints, lightCoords, overlayCoords, outlineColor); + poseStack.popPose(); + } else { + submitNodeCollector.submitBlockModel(poseStack, renderType, modelPartsCopy, meshCopy, tints, lightCoords, overlayCoords, outlineColor); + } + + ci.cancel(); + } + } +} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/BlockRenderDispatcherMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/BlockRenderDispatcherMixin.java deleted file mode 100644 index 67dab8f7c77..00000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/BlockRenderDispatcherMixin.java +++ /dev/null @@ -1,27 +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 org.spongepowered.asm.mixin.Mixin; - -import net.minecraft.client.renderer.block.BlockRenderDispatcher; - -import net.fabricmc.fabric.api.client.renderer.v1.render.FabricBlockRenderDispatcher; - -@Mixin(BlockRenderDispatcher.class) -abstract class BlockRenderDispatcherMixin implements FabricBlockRenderDispatcher { -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/BlockStateModelWrapperMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/BlockStateModelWrapperMixin.java new file mode 100644 index 00000000000..5d597000213 --- /dev/null +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/BlockStateModelWrapperMixin.java @@ -0,0 +1,63 @@ +/* + * 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 org.joml.Matrix4fc; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.client.color.block.BlockTintSource; +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.BlockModelRenderState; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; +import net.minecraft.client.renderer.block.model.BlockDisplayContext; +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.client.renderer.block.model.BlockStateModelWrapper; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; + +import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter; + +@Mixin(BlockStateModelWrapper.class) +abstract class BlockStateModelWrapperMixin implements BlockModel { + @Shadow + @Final + private BlockStateModel model; + @Shadow + @Final + private List tints; + @Shadow + @Final + private Matrix4fc transformation; + + @Shadow + abstract void updateTints(BlockModelRenderState renderState, BlockState blockState); + + @Overwrite + @Override + public void update(BlockModelRenderState output, BlockState blockState, BlockDisplayContext displayContext, final long seed) { + QuadEmitter emitter = output.setupMesh(transformation, model.hasMaterialFlag(BakedQuad.FLAG_TRANSLUCENT)); + // TODO FRAPI 26.1: somehow pass the level and pos here when available? + model.emitQuads(emitter, BlockAndTintGetter.EMPTY, BlockPos.ZERO, blockState, output.scratchRandomSource(seed), _ -> false); + updateTints(output, blockState); + } +} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/ItemFrameRendererMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/ItemFrameRendererMixin.java deleted file mode 100644 index fa4fe2609d8..00000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/ItemFrameRendererMixin.java +++ /dev/null @@ -1,42 +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 com.llamalad7.mixinextras.sugar.Local; -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.Redirect; - -import net.minecraft.client.renderer.SubmitNodeCollector; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.entity.ItemFrameRenderer; -import net.minecraft.client.renderer.rendertype.RenderType; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.EmptyBlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; - -@Mixin(ItemFrameRenderer.class) -abstract class ItemFrameRendererMixin { - // Provide the BlockState as context. - @Redirect(method = "submit(Lnet/minecraft/client/renderer/entity/state/ItemFrameRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/state/CameraRenderState;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/SubmitNodeCollector;submitBlockModel(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/rendertype/RenderType;Lnet/minecraft/client/renderer/block/model/BlockStateModel;FFFIII)V")) - private void renderProxy(SubmitNodeCollector submitNodeCollector, PoseStack poseStack, RenderType renderType, BlockStateModel model, float r, float g, float b, int light, int overlay, int outlineColor, @Local(name = "fakeBlockState") BlockState fakeBlockState) { - // The vertex consumer is for a special layer that renders solid, but vanilla has no equivalent - // cutout/translucent layers that we can use here without risking compatibility. - submitNodeCollector.submitBlockModel(poseStack, blockLayer -> renderType, model, r, g, b, light, overlay, outlineColor, EmptyBlockAndTintGetter.INSTANCE, BlockPos.ZERO, fakeBlockState); - } -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/ModelBlockRendererMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/ModelBlockRendererMixin.java deleted file mode 100644 index 0b23f85ba67..00000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/ModelBlockRendererMixin.java +++ /dev/null @@ -1,27 +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 org.spongepowered.asm.mixin.Mixin; - -import net.minecraft.client.renderer.block.ModelBlockRenderer; - -import net.fabricmc.fabric.api.client.renderer.v1.render.FabricModelBlockRenderer; - -@Mixin(ModelBlockRenderer.class) -abstract class ModelBlockRendererMixin implements FabricModelBlockRenderer { -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/MushroomCowMushroomLayerMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/MushroomCowMushroomLayerMixin.java deleted file mode 100644 index 6e410d6b2f7..00000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/MushroomCowMushroomLayerMixin.java +++ /dev/null @@ -1,40 +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 com.llamalad7.mixinextras.sugar.Local; -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.Redirect; - -import net.minecraft.client.renderer.SubmitNodeCollector; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.entity.layers.MushroomCowMushroomLayer; -import net.minecraft.client.renderer.rendertype.RenderType; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.EmptyBlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; - -@Mixin(MushroomCowMushroomLayer.class) -abstract class MushroomCowMushroomLayerMixin { - // Fix tinted quads being rendered completely black and provide the BlockState as context. - @Redirect(method = "submitMushroomBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/SubmitNodeCollector;submitBlockModel(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/rendertype/RenderType;Lnet/minecraft/client/renderer/block/model/BlockStateModel;FFFIII)V")) - private void renderProxy(SubmitNodeCollector submitNodeCollector, PoseStack poseStack, RenderType renderType, BlockStateModel model, float r, float g, float b, int light, int overlay, int outlineColor, @Local(argsOnly = true) BlockState blockState) { - submitNodeCollector.submitBlockModel(poseStack, _ -> renderType, model, 1, 1, 1, light, overlay, outlineColor, EmptyBlockAndTintGetter.INSTANCE, BlockPos.ZERO, blockState); - } -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/SectionCompilerMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/SectionCompilerMixin.java new file mode 100644 index 00000000000..704ea347cc9 --- /dev/null +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/SectionCompilerMixin.java @@ -0,0 +1,81 @@ +/* + * 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.Map; + +import com.llamalad7.mixinextras.sugar.Local; +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.VertexSorting; +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.CallbackInfoReturnable; + +import net.minecraft.client.color.block.BlockColors; +import net.minecraft.client.renderer.SectionBufferBuilderPack; +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.dispatch.BlockStateModel; +import net.minecraft.client.renderer.chunk.ChunkSectionLayer; +import net.minecraft.client.renderer.chunk.RenderSectionRegion; +import net.minecraft.client.renderer.chunk.SectionCompiler; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +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.QuadEmitter; +import net.fabricmc.fabric.api.client.renderer.v1.render.AltModelBlockRenderer; + +@Mixin(SectionCompiler.class) +abstract class SectionCompilerMixin { + @Shadow + @Final + private boolean ambientOcclusion; + @Shadow + @Final + private BlockColors blockColors; + + @Shadow + protected abstract BufferBuilder getOrBeginLayer( + Map startedLayers, + SectionBufferBuilderPack buffers, + ChunkSectionLayer layer + ); + + @Inject(method = "compile", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/BlockPos;betweenClosed(Lnet/minecraft/core/BlockPos;Lnet/minecraft/core/BlockPos;)Ljava/lang/Iterable;")) + private void beforeLoopCompile(SectionPos sectionPos, RenderSectionRegion region, VertexSorting vertexSorting, SectionBufferBuilderPack builders, CallbackInfoReturnable cir, @Local(name = "startedLayers") Map startedLayers, @Share("altBlockRenderer") LocalRef altBlockRenderer, @Share("altQuadOutput") LocalRef altQuadOutput) { + altBlockRenderer.set(Renderer.get().altModelBlockRenderer(ambientOcclusion, true, blockColors)); + altQuadOutput.set(Renderer.get().quadEmitter(quad -> { + BufferBuilder builder = getOrBeginLayer(startedLayers, builders, quad.chunkLayer()); + quad.buffer(OverlayTexture.NO_OVERLAY, builder); + })); + } + + @Redirect(method = "compile", 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) { + 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/block/render/SnowGolemHeadLayerMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/SnowGolemHeadLayerMixin.java deleted file mode 100644 index 9a49f6d70d8..00000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/SnowGolemHeadLayerMixin.java +++ /dev/null @@ -1,49 +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 com.llamalad7.mixinextras.sugar.Local; -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.Redirect; - -import net.minecraft.client.renderer.SubmitNodeCollector; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.entity.layers.SnowGolemHeadLayer; -import net.minecraft.client.renderer.entity.state.SnowGolemRenderState; -import net.minecraft.client.renderer.rendertype.RenderType; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.EmptyBlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; - -import net.fabricmc.fabric.api.client.renderer.v1.render.ChunkSectionLayerHelper; - -@Mixin(SnowGolemHeadLayer.class) -abstract class SnowGolemHeadLayerMixin { - @Redirect(method = "submit(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;ILnet/minecraft/client/renderer/entity/state/SnowGolemRenderState;FF)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/SubmitNodeCollector;submitBlockModel(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/rendertype/RenderType;Lnet/minecraft/client/renderer/block/model/BlockStateModel;FFFIII)V")) - private void renderProxy(SubmitNodeCollector submitNodeCollector, PoseStack poseStack, RenderType renderType, BlockStateModel model, float r, float g, float b, int light, int overlay, int outlineColor, @Local(argsOnly = true) SnowGolemRenderState renderState, @Local(name = "pumpkinBlockState") BlockState pumpkinBlockState) { - // If true, the chunk layer is an outline chunk layer, and we want all geometry to use this chunk layer. - if (renderState.appearsGlowing() && renderState.isInvisible) { - // Fix tinted quads being rendered completely black and provide the BlockState as context. - submitNodeCollector.submitBlockModel(poseStack, _ -> renderType, model, 1, 1, 1, light, overlay, outlineColor, EmptyBlockAndTintGetter.INSTANCE, BlockPos.ZERO, pumpkinBlockState); - } else { - // Support multi-chunk layer models, fix tinted quads being rendered completely black, and provide the BlockState as context. - submitNodeCollector.submitBlockModel(poseStack, ChunkSectionLayerHelper::getEntityBlockLayer, model, 1, 1, 1, light, overlay, outlineColor, EmptyBlockAndTintGetter.INSTANCE, BlockPos.ZERO, pumpkinBlockState); - } - } -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/SubmitNodeCollectionMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/SubmitNodeCollectionMixin.java deleted file mode 100644 index fdfe0e55a1e..00000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/SubmitNodeCollectionMixin.java +++ /dev/null @@ -1,94 +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.ArrayList; -import java.util.List; -import java.util.function.Function; - -import com.mojang.blaze3d.vertex.PoseStack; -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.Minecraft; -import net.minecraft.client.renderer.OrderedSubmitNodeCollector; -import net.minecraft.client.renderer.SubmitNodeCollection; -import net.minecraft.client.renderer.SubmitNodeStorage; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; -import net.minecraft.client.renderer.rendertype.RenderType; -import net.minecraft.core.BlockPos; -import net.minecraft.world.item.ItemDisplayContext; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; - -import net.fabricmc.fabric.impl.client.renderer.ExtendedBlockModelSubmit; -import net.fabricmc.fabric.impl.client.renderer.ExtendedBlockSubmit; -import net.fabricmc.fabric.impl.client.renderer.SubmitNodeCollectionExtension; - -@Mixin(SubmitNodeCollection.class) -abstract class SubmitNodeCollectionMixin implements OrderedSubmitNodeCollector, SubmitNodeCollectionExtension { - @Shadow - @Final - private SubmitNodeStorage submitNodeStorage; - @Shadow - private boolean wasUsed; - - @Unique - private final List extendedBlockSubmits = new ArrayList<>(); - @Unique - private final List extendedBlockModelSubmits = new ArrayList<>(); - - @Override - public void submitBlock(PoseStack poseStack, BlockState state, int light, int overlay, int outlineColor, BlockAndTintGetter level, BlockPos pos) { - wasUsed = true; - extendedBlockSubmits.add(new ExtendedBlockSubmit(poseStack.last().copy(), state, light, overlay, outlineColor, - level, pos)); - Minecraft.getInstance().getModelManager().specialBlockModelRenderer().renderByBlock(state.getBlock(), ItemDisplayContext.NONE, - poseStack, submitNodeStorage, light, overlay, outlineColor); - } - - @Override - public void submitBlockModel(PoseStack poseStack, Function renderTypeFunction, BlockStateModel model, float r, float g, float b, int light, int overlay, int outlineColor, BlockAndTintGetter level, BlockPos pos, BlockState state) { - wasUsed = true; - extendedBlockModelSubmits.add(new ExtendedBlockModelSubmit( - poseStack.last().copy(), - renderTypeFunction, model, r, g, b, light, overlay, outlineColor, - level, pos, state)); - } - - @Override - public List fabric_getExtendedBlockSubmits() { - return extendedBlockSubmits; - } - - @Override - public List fabric_getExtendedBlockModelSubmits() { - return extendedBlockModelSubmits; - } - - @Inject(method = "clear", at = @At("RETURN")) - private void onReturnClear(CallbackInfo ci) { - extendedBlockSubmits.clear(); - extendedBlockModelSubmits.clear(); - } -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/SubmitNodeStorageMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/SubmitNodeStorageMixin.java deleted file mode 100644 index 2adc78c7d15..00000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/SubmitNodeStorageMixin.java +++ /dev/null @@ -1,48 +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 org.spongepowered.asm.mixin.Mixin; - -import net.minecraft.client.renderer.SubmitNodeCollector; -import net.minecraft.client.renderer.SubmitNodeStorage; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; -import net.minecraft.client.renderer.rendertype.RenderType; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; - -@Mixin(SubmitNodeStorage.class) -abstract class SubmitNodeStorageMixin implements SubmitNodeCollector { - @Override - public void submitBlock(PoseStack poseStack, BlockState state, int light, int overlay, int outlineColor, BlockAndTintGetter level, BlockPos pos) { - order(0).submitBlock(poseStack, state, light, overlay, outlineColor, - level, pos); - } - - @Override - public void submitBlockModel(PoseStack poseStack, Function renderTypeFunction, BlockStateModel model, float r, float g, float b, int light, int overlay, int outlineColor, BlockAndTintGetter level, BlockPos pos, BlockState state) { - order(0).submitBlockModel( - poseStack, - renderTypeFunction, model, r, g, b, light, overlay, outlineColor, - level, pos, state); - } -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/item/BlockModelWrapperMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/item/BlockModelWrapperMixin.java deleted file mode 100644 index 1197fe1469e..00000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/item/BlockModelWrapperMixin.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.item; - -import com.llamalad7.mixinextras.sugar.Local; -import org.jspecify.annotations.Nullable; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -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.multiplayer.ClientLevel; -import net.minecraft.client.renderer.ItemBlockRenderTypes; -import net.minecraft.client.renderer.Sheets; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; -import net.minecraft.client.renderer.item.BlockModelWrapper; -import net.minecraft.client.renderer.item.ItemModel; -import net.minecraft.client.renderer.item.ItemModelResolver; -import net.minecraft.client.renderer.item.ItemStackRenderState; -import net.minecraft.client.resources.model.SpriteGetter; -import net.minecraft.world.entity.ItemOwner; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.ItemDisplayContext; -import net.minecraft.world.item.ItemStack; - -import net.fabricmc.fabric.api.client.renderer.v1.mesh.Mesh; -import net.fabricmc.fabric.impl.client.renderer.BlockModelWrapperExtension; - -@Mixin(BlockModelWrapper.class) -abstract class BlockModelWrapperMixin implements ItemModel, BlockModelWrapperExtension { - @Shadow - @Final - @Mutable - private boolean animated; - - @Unique - @Nullable - private Mesh mesh; - - @Inject(method = "update", at = @At("RETURN")) - private void onReturnUpdate(final ItemStackRenderState output, final ItemStack item, final ItemModelResolver resolver, final ItemDisplayContext displayContext, final @Nullable ClientLevel level, final @Nullable ItemOwner owner, final int seed, CallbackInfo ci, @Local(name = "layer") ItemStackRenderState.LayerRenderState layer) { - if (mesh != null) { - // This logic matches that of ITEM_RENDER_TYPE_GETTER and BLOCK_RENDER_TYPE_GETTER - ChunkSectionLayer defaultSectionLayer; - - if (item.getItem() instanceof BlockItem blockItem) { - defaultSectionLayer = ItemBlockRenderTypes.getChunkRenderType(blockItem.getBlock().defaultBlockState()); - } else { - defaultSectionLayer = ChunkSectionLayer.TRANSLUCENT; - } - - layer.setRenderTypeGetter((quadAtlas, sectionLayer) -> { - return switch (quadAtlas) { - case BLOCK -> { - if (sectionLayer == null) { - sectionLayer = defaultSectionLayer; - } - - if (sectionLayer != ChunkSectionLayer.TRANSLUCENT) { - yield Sheets.cutoutBlockSheet(); - } - - yield Sheets.translucentBlockItemSheet(); - } - case ITEM -> Sheets.translucentItemSheet(); - }; - }); - - mesh.outputTo(layer.emitter()); - } - } - - @Override - public void fabric_setMesh(Mesh mesh, SpriteGetter spriteGetter) { - this.mesh = mesh; - - if (!animated) { - mesh.forEach(quad -> { - if (animated) { - return; - } - - ItemStackRenderState.FoilType glint = quad.foilType(); - - if ((glint != null && glint != ItemStackRenderState.FoilType.NONE) - || spriteGetter.spriteFinder(quad.atlas().getTextureId()).find(quad).contents().isAnimated()) { - animated = true; - } - }); - } - } -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/item/BlockModelWrapperUnbakedMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/item/BlockModelWrapperUnbakedMixin.java deleted file mode 100644 index 357a11f7286..00000000000 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/item/BlockModelWrapperUnbakedMixin.java +++ /dev/null @@ -1,54 +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.item; - -import com.llamalad7.mixinextras.injector.ModifyExpressionValue; -import com.llamalad7.mixinextras.sugar.Share; -import com.llamalad7.mixinextras.sugar.ref.LocalRef; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; - -import net.minecraft.client.renderer.item.BlockModelWrapper; -import net.minecraft.client.renderer.item.ItemModel; -import net.minecraft.client.resources.model.QuadCollection; - -import net.fabricmc.fabric.api.client.renderer.v1.mesh.Mesh; -import net.fabricmc.fabric.api.client.renderer.v1.model.MeshQuadCollection; -import net.fabricmc.fabric.impl.client.renderer.BlockModelWrapperExtension; - -@Mixin(BlockModelWrapper.Unbaked.class) -abstract class BlockModelWrapperUnbakedMixin { - @ModifyExpressionValue(method = "bake", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/ResolvedModel;bakeTopGeometry(Lnet/minecraft/client/renderer/block/model/TextureSlots;Lnet/minecraft/client/resources/model/ModelBaker;Lnet/minecraft/client/resources/model/ModelState;)Lnet/minecraft/client/resources/model/QuadCollection;")) - private QuadCollection captureMesh(QuadCollection geometry, @Share("mesh") LocalRef meshRef) { - if (geometry instanceof MeshQuadCollection meshQuadCollection) { - meshRef.set(meshQuadCollection.getMesh()); - } - - return geometry; - } - - @ModifyExpressionValue(method = "bake", at = @At(value = "NEW", target = "net/minecraft/client/renderer/item/BlockModelWrapper")) - private BlockModelWrapper injectMesh(BlockModelWrapper model, ItemModel.BakingContext context, @Share("mesh") LocalRef meshRef) { - Mesh mesh = meshRef.get(); - - if (mesh != null) { - ((BlockModelWrapperExtension) model).fabric_setMesh(mesh, context.blockModelBaker().sprites()); - } - - return model; - } -} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/item/CuboidItemModelWrapperMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/item/CuboidItemModelWrapperMixin.java new file mode 100644 index 00000000000..954aacace52 --- /dev/null +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/item/CuboidItemModelWrapperMixin.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.mixin.client.renderer.item; + +import com.llamalad7.mixinextras.sugar.Local; +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.multiplayer.ClientLevel; +import net.minecraft.client.renderer.item.CuboidItemModelWrapper; +import net.minecraft.client.renderer.item.ItemModel; +import net.minecraft.client.renderer.item.ItemModelResolver; +import net.minecraft.client.renderer.item.ItemStackRenderState; +import net.minecraft.client.resources.model.geometry.QuadCollection; +import net.minecraft.world.entity.ItemOwner; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; + +import net.fabricmc.fabric.api.client.renderer.v1.model.MeshQuadCollection; + +// NOTE: We intentionally do not validate the mesh like vanilla validates the quad list. Nowadays, +// both vanilla and FRAPI allow using multiple atlases from within the same layer, so perhaps the +// vanilla validation is a holdover from older versions. Regardless, we want to allow this for +// meshes. +@Mixin(CuboidItemModelWrapper.class) +abstract class CuboidItemModelWrapperMixin implements ItemModel { + @Shadow + @Final + private QuadCollection quads; + + @Inject(method = "update", at = @At("RETURN")) + private void onReturnUpdate(ItemStackRenderState output, ItemStack item, ItemModelResolver resolver, ItemDisplayContext displayContext, ClientLevel level, ItemOwner owner, int seed, CallbackInfo ci, @Local(name = "layer") ItemStackRenderState.LayerRenderState layer) { + if (quads instanceof MeshQuadCollection meshQuadCollection) { + meshQuadCollection.getMesh().outputTo(layer.emitter()); + } + } +} diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/item/ItemStackRenderStateLayerRenderStateMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/item/ItemStackRenderStateLayerRenderStateMixin.java index 9c1375ae153..3d5c382ccca 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/item/ItemStackRenderStateLayerRenderStateMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/item/ItemStackRenderStateLayerRenderStateMixin.java @@ -16,12 +16,75 @@ package net.fabricmc.fabric.mixin.client.renderer.item; +import java.util.List; + +import com.mojang.blaze3d.vertex.PoseStack; +import org.jspecify.annotations.Nullable; 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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import net.minecraft.client.renderer.SubmitNodeCollector; 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.Renderer; +import net.fabricmc.fabric.api.client.renderer.v1.mesh.MutableMesh; +import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter; import net.fabricmc.fabric.api.client.renderer.v1.render.FabricLayerRenderState; +import net.fabricmc.fabric.impl.client.renderer.LayerRenderStateExtension; @Mixin(ItemStackRenderState.LayerRenderState.class) -abstract class ItemStackRenderStateLayerRenderStateMixin implements FabricLayerRenderState { +abstract class ItemStackRenderStateLayerRenderStateMixin implements FabricLayerRenderState, LayerRenderStateExtension { + @Unique + @Nullable + private MutableMesh mutableMesh; + + @Override + public QuadEmitter emitter() { + if (mutableMesh == null) { + mutableMesh = Renderer.get().mutableMesh(); + } + + return mutableMesh.emitter(); + } + + @Override + @Nullable + public MutableMesh fabric_getMutableMesh() { + return mutableMesh; + } + + @Inject(method = "clear()V", at = @At("RETURN")) + private void onReturnClear(CallbackInfo ci) { + if (mutableMesh != null) { + mutableMesh.clear(); + } + } + + @Redirect(method = "submit", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/SubmitNodeCollector;submitItem(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/world/item/ItemDisplayContext;III[ILjava/util/List;Lnet/minecraft/client/renderer/item/ItemStackRenderState$FoilType;)V")) + private void submitItemProxy( + SubmitNodeCollector submitNodeCollector, + PoseStack poseStack, + ItemDisplayContext displayContext, + int light, + int overlay, + int outlineColor, + int[] tints, + List quads, + ItemStackRenderState.FoilType foilType + ) { + if (mutableMesh != null && mutableMesh.size() > 0) { + // We don't have to copy the mesh here because vanilla doesn't copy the quad list either. + submitNodeCollector.submitItem(poseStack, displayContext, light, overlay, outlineColor, tints, quads, + mutableMesh, foilType); + } else { + submitNodeCollector.submitItem(poseStack, displayContext, light, overlay, outlineColor, tints, quads, + foilType); + } + } } diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemStackRenderStateMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/item/ItemStackRenderStateMixin.java similarity index 83% rename from fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemStackRenderStateMixin.java rename to fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/item/ItemStackRenderStateMixin.java index 7518fbf6d2b..9aeba468a69 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemStackRenderStateMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/item/ItemStackRenderStateMixin.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.mixin.client.indigo.renderer; +package net.fabricmc.fabric.mixin.client.renderer.item; import java.util.function.Consumer; @@ -31,9 +31,9 @@ import net.minecraft.client.renderer.item.ItemStackRenderState; -import net.fabricmc.fabric.impl.client.indigo.renderer.accessor.AccessLayerRenderState; -import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableMeshImpl; -import net.fabricmc.fabric.impl.client.indigo.renderer.render.QuadToPosPipe; +import net.fabricmc.fabric.api.client.renderer.v1.mesh.MutableMesh; +import net.fabricmc.fabric.impl.client.renderer.LayerRenderStateExtension; +import net.fabricmc.fabric.impl.client.renderer.QuadToPosPipe; @Mixin(ItemStackRenderState.class) abstract class ItemStackRenderStateMixin { @@ -44,12 +44,12 @@ private void afterInitVecLoad(Consumer posConsumer, CallbackInfo ci, @Inject(method = "visitExtents(Ljava/util/function/Consumer;)V", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack$Pose;setIdentity()V")) private void afterLayerLoad(Consumer posConsumer, CallbackInfo ci, @Local(name = "scratch") Vector3f vec, @Local(name = "layer") ItemStackRenderState.LayerRenderState layer, @Local(name = "poseTransform") Matrix4f matrix, @Share("pipe") LocalRef pipeRef) { - MutableMeshImpl mutableMesh = ((AccessLayerRenderState) layer).fabric_getMutableMesh(); + MutableMesh mutableMesh = ((LayerRenderStateExtension) layer).fabric_getMutableMesh(); - if (mutableMesh.size() > 0) { + if (mutableMesh != null && mutableMesh.size() > 0) { QuadToPosPipe pipe = pipeRef.get(); pipe.matrix = matrix; - // Use the mutable version here as it does not use a ThreadLocal or cursor stack + // Use the mutable version here as it does not use a ThreadLocal or cursor stack, at least in Indigo mutableMesh.forEachMutable(pipe); } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/SpriteGetterMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/MaterialBakerMixin.java similarity index 75% rename from fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/SpriteGetterMixin.java rename to fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/MaterialBakerMixin.java index 7e087672502..7902454ae3c 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/SpriteGetterMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/MaterialBakerMixin.java @@ -18,10 +18,10 @@ import org.spongepowered.asm.mixin.Mixin; -import net.minecraft.client.resources.model.SpriteGetter; +import net.minecraft.client.resources.model.sprite.MaterialBaker; -import net.fabricmc.fabric.api.client.renderer.v1.sprite.FabricSpriteGetter; +import net.fabricmc.fabric.api.client.renderer.v1.sprite.FabricMaterialBaker; -@Mixin(SpriteGetter.class) -interface SpriteGetterMixin extends FabricSpriteGetter { +@Mixin(MaterialBaker.class) +interface MaterialBakerMixin extends FabricMaterialBaker { } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/ModelManager1Mixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/ModelManager1Mixin.java index c5af9a1d2dd..7cdcbb4c20f 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/ModelManager1Mixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/sprite/ModelManager1Mixin.java @@ -23,19 +23,19 @@ import org.spongepowered.asm.mixin.Unique; import net.minecraft.client.renderer.texture.SpriteLoader; -import net.minecraft.client.renderer.texture.TextureAtlas; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.SpriteGetter; +import net.minecraft.client.resources.model.sprite.Material; +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(targets = "net.minecraft.client.resources.model.ModelManager$1") -abstract class ModelManager1Mixin implements SpriteGetter { +abstract class ModelManager1Mixin implements FabricMaterialBaker { @Shadow @Final - private TextureAtlasSprite blockMissing; + private Material.Baked blockMissing; @Shadow @Final SpriteLoader.Preparations val$blockAtlas; @@ -48,10 +48,10 @@ abstract class ModelManager1Mixin implements SpriteGetter { private volatile MissingSpriteFinderImpl missingSpriteFinder; @Override - public SpriteFinder spriteFinder(Identifier atlasTextureId) { - if (atlasTextureId.equals(TextureAtlas.LOCATION_BLOCKS)) { + public SpriteFinder spriteFinder(Identifier atlasId) { + if (atlasId.equals(AtlasIds.BLOCKS)) { return val$blockAtlas.spriteFinder(); - } else if (atlasTextureId.equals(TextureAtlas.LOCATION_ITEMS)) { + } else if (atlasId.equals(AtlasIds.ITEMS)) { return val$itemAtlas.spriteFinder(); } @@ -62,7 +62,7 @@ public SpriteFinder spriteFinder(Identifier atlasTextureId) { result = missingSpriteFinder; if (result == null) { - missingSpriteFinder = result = new MissingSpriteFinderImpl(blockMissing); + missingSpriteFinder = result = new MissingSpriteFinderImpl(blockMissing.sprite()); } } } diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/OrderedSubmitNodeCollectorMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/submit/OrderedSubmitNodeCollectorMixin.java similarity index 93% rename from fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/OrderedSubmitNodeCollectorMixin.java rename to fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/submit/OrderedSubmitNodeCollectorMixin.java index 96c1dc67215..65febe63879 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/block/render/OrderedSubmitNodeCollectorMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/submit/OrderedSubmitNodeCollectorMixin.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.mixin.client.renderer.block.render; +package net.fabricmc.fabric.mixin.client.renderer.submit; import org.spongepowered.asm.mixin.Mixin; 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 new file mode 100644 index 00000000000..7422ec3e3ef --- /dev/null +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/submit/SubmitNodeCollectionMixin.java @@ -0,0 +1,79 @@ +/* + * 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.submit; + +import java.util.ArrayList; +import java.util.List; + +import com.mojang.blaze3d.vertex.PoseStack; +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.OrderedSubmitNodeCollector; +import net.minecraft.client.renderer.SubmitNodeCollection; +import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart; +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; +import net.fabricmc.fabric.api.client.renderer.v1.render.FabricSubmitNodeCollection; + +@Mixin(SubmitNodeCollection.class) +abstract class SubmitNodeCollectionMixin implements OrderedSubmitNodeCollector, FabricSubmitNodeCollection { + @Shadow + private boolean wasUsed; + + @Unique + private final List extendedBlockModelSubmits = new ArrayList<>(); + @Unique + private final List extendedItemSubmits = new ArrayList<>(); + + @Override + public void submitBlockModel(PoseStack poseStack, RenderType renderType, List parts, Mesh mesh, int[] tintLayers, int lightCoords, int overlayCoords, int outlineColor) { + wasUsed = true; + extendedBlockModelSubmits.add(new ExtendedBlockModelSubmit(poseStack.last().copy(), renderType, parts, mesh, tintLayers, lightCoords, overlayCoords, outlineColor)); + } + + @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)); + } + + @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(); + } +} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/SubmitNodeStorageMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/submit/SubmitNodeStorageMixin.java similarity index 50% rename from fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/SubmitNodeStorageMixin.java rename to fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/submit/SubmitNodeStorageMixin.java index a75d9101fce..7a4dd9c5433 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/SubmitNodeStorageMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/client/renderer/submit/SubmitNodeStorageMixin.java @@ -14,52 +14,33 @@ * limitations under the License. */ -package net.fabricmc.fabric.mixin.client.indigo.renderer; +package net.fabricmc.fabric.mixin.client.renderer.submit; import java.util.List; import com.mojang.blaze3d.vertex.PoseStack; import org.spongepowered.asm.mixin.Mixin; -import net.minecraft.client.renderer.OrderedSubmitNodeCollector; import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.SubmitNodeStorage; -import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart; 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; -import net.fabricmc.fabric.api.client.renderer.v1.render.ItemRenderTypeGetter; -import net.fabricmc.fabric.impl.client.indigo.renderer.accessor.AccessOrderedSubmitNodeCollector; @Mixin(SubmitNodeStorage.class) -abstract class SubmitNodeStorageMixin implements SubmitNodeCollector, AccessOrderedSubmitNodeCollector { +abstract class SubmitNodeStorageMixin implements SubmitNodeCollector { @Override - public void fabric_submitItem( - PoseStack poseStack, - ItemDisplayContext displayContext, - int light, - int overlay, - int outlineColors, - int[] tintLayers, - List quads, - RenderType renderType, - ItemStackRenderState.FoilType foilType, - MeshView mesh, - ItemRenderTypeGetter renderTypeGetter - ) { - OrderedSubmitNodeCollector nodeCollector = order(0); + public void submitBlockModel(PoseStack poseStack, RenderType renderType, List parts, Mesh mesh, int[] tintLayers, int lightCoords, int overlayCoords, int outlineColor) { + order(0).submitBlockModel(poseStack, renderType, parts, mesh, tintLayers, lightCoords, overlayCoords, outlineColor); + } - if (nodeCollector instanceof AccessOrderedSubmitNodeCollector access) { - access.fabric_submitItem(poseStack, displayContext, light, overlay, outlineColors, tintLayers, quads, - renderType, - foilType, mesh, renderTypeGetter); - } else { - nodeCollector.submitItem(poseStack, displayContext, light, overlay, outlineColors, tintLayers, quads, - renderType, - foilType - ); - } + @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 a7c8d9e8d40..fc450edeeab 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,13 +1,13 @@ classTweaker v1 official -accessible class net/minecraft/client/renderer/block/model/multipart/MultiPartModel$SharedBakedState -accessible method net/minecraft/client/resources/model/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 -transitive-inject-interface net/minecraft/client/renderer/block/model/BlockModelPart net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockModelPart -transitive-inject-interface net/minecraft/client/renderer/block/BlockModelShaper net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockModelShaper -transitive-inject-interface net/minecraft/client/renderer/block/model/BlockStateModel net/fabricmc/fabric/api/client/renderer/v1/model/FabricBlockStateModel -transitive-inject-interface net/minecraft/client/renderer/block/ModelBlockRenderer net/fabricmc/fabric/api/client/renderer/v1/render/FabricModelBlockRenderer -transitive-inject-interface net/minecraft/client/renderer/block/BlockRenderDispatcher net/fabricmc/fabric/api/client/renderer/v1/render/FabricBlockRenderDispatcher +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 +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/resources/model/SpriteGetter net/fabricmc/fabric/api/client/renderer/v1/sprite/FabricSpriteGetter -transitive-inject-interface net/minecraft/client/renderer/texture/TextureAtlas net/fabricmc/fabric/api/client/renderer/v1/sprite/FabricTextureAtlas +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 58c1865f8e4..98d7d604691 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 @@ -3,33 +3,31 @@ "package": "net.fabricmc.fabric.mixin.client.renderer", "compatibilityLevel": "JAVA_25", "client": [ - "block.model.BlockModelPartMixin", "block.model.BlockStateModelMixin", - "block.model.SimpleModelWrapperMixin", - "block.model.MultiPartModelSharedBakedStateAccessor", + "block.model.BlockStateModelPartMixin", "block.model.MultiPartModelMixin", + "block.model.MultiPartModelSharedBakedStateAccessor", + "block.model.SimpleModelWrapperMixin", "block.model.SingleVariantMixin", "block.model.WeightedVariantsMixin", - "block.particle.TerrainParticleMixin", "block.particle.BlockMarkerMixin", - "block.particle.BlockModelShaperMixin", + "block.particle.BlockStateModelSetMixin", "block.particle.ScreenEffectRendererMixin", - "block.render.SubmitNodeCollectionMixin", - "block.render.ModelBlockRendererMixin", - "block.render.BlockRenderDispatcherMixin", + "block.particle.TerrainParticleMixin", "block.render.BlockFeatureRendererMixin", - "block.render.ItemFrameRendererMixin", - "block.render.MushroomCowMushroomLayerMixin", - "block.render.SubmitNodeStorageMixin", - "block.render.OrderedSubmitNodeCollectorMixin", - "block.render.SnowGolemHeadLayerMixin", - "item.BlockModelWrapperMixin", - "item.BlockModelWrapperUnbakedMixin", + "block.render.BlockModelRenderStateMixin", + "block.render.BlockStateModelWrapperMixin", + "block.render.SectionCompilerMixin", + "item.CuboidItemModelWrapperMixin", "item.ItemStackRenderStateLayerRenderStateMixin", + "item.ItemStackRenderStateMixin", + "sprite.MaterialBakerMixin", "sprite.ModelManager1Mixin", - "sprite.SpriteGetterMixin", + "sprite.SpriteLoaderPreparationsMixin", "sprite.TextureAtlasMixin", - "sprite.SpriteLoaderPreparationsMixin" + "submit.OrderedSubmitNodeCollectorMixin", + "submit.SubmitNodeCollectionMixin", + "submit.SubmitNodeStorageMixin" ], "injectors": { "defaultRequire": 1 diff --git a/fabric-renderer-api-v1/src/client/resources/fabric.mod.json b/fabric-renderer-api-v1/src/client/resources/fabric.mod.json index a6587876eda..11461d2d1b4 100644 --- a/fabric-renderer-api-v1/src/client/resources/fabric.mod.json +++ b/fabric-renderer-api-v1/src/client/resources/fabric.mod.json @@ -22,7 +22,7 @@ }, "depends": { "fabricloader": ">=0.18.4", - "minecraft": ">=1.21.5-beta.1", + "minecraft": ">=26.1-rc.2", "fabric-api-base": "*", "fabric-rendering-v1": "*", "fabric-transitive-access-wideners-v1": "*" diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java index dc75cddd9f1..28e63be75cb 100644 --- a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java @@ -24,7 +24,7 @@ import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.BlockAndLightGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -103,7 +103,7 @@ public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { // The frames don't look exactly like the block they are mimicking, // but the goal here is just to test the behavior with the pillar's connected textures. ;-) @Override - public BlockState getAppearance(BlockState state, BlockAndTintGetter renderView, BlockPos pos, Direction side, @Nullable BlockState sourceState, @Nullable BlockPos sourcePos) { + public BlockState getAppearance(BlockState state, BlockAndLightGetter renderView, BlockPos pos, Direction side, @Nullable BlockState sourceState, @Nullable BlockPos sourcePos) { // For this specific block, the render data works on both the client and the server, so let's use that. if (((FabricBlockGetter) renderView).getBlockEntityRenderData(pos) instanceof Block mimickedBlock) { return mimickedBlock.defaultBlockState(); diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/BiomeDependentBlockStateModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/BiomeDependentBlockStateModel.java index 56e49de7463..3a58cb467c2 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/BiomeDependentBlockStateModel.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/BiomeDependentBlockStateModel.java @@ -23,16 +23,17 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import org.jspecify.annotations.Nullable; -import net.minecraft.client.renderer.block.model.BlockModelPart; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; +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.resources.model.ModelBaker; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.registries.Registries; import net.minecraft.tags.TagKey; import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.state.BlockState; @@ -73,20 +74,25 @@ public Object createGeometryKey(BlockAndTintGetter level, BlockPos pos, BlockSta } @Override - public void collectParts(RandomSource random, List parts) { + public void collectParts(RandomSource random, List parts) { } @Override - public TextureAtlasSprite particleIcon() { - return regularModel.particleIcon(); + public Material.Baked particleMaterial() { + return regularModel.particleMaterial(); } @Override - public TextureAtlasSprite particleIcon(BlockAndTintGetter level, BlockPos pos, BlockState state) { + public @BakedQuad.MaterialFlags int materialFlags() { + return regularModel.materialFlags() | biomeModel.materialFlags(); + } + + @Override + public Material.Baked particleMaterial(BlockAndTintGetter level, BlockPos pos, BlockState state) { if (((FabricBlockGetter) level).hasBiomes() && ((FabricBlockGetter) level).getBiomeFabric(pos).is(biomeTag)) { - return biomeModel.particleIcon(level, pos, state); + return biomeModel.particleMaterial(level, pos, state); } else { - return regularModel.particleIcon(level, pos, state); + return regularModel.particleMaterial(level, pos, state); } } diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/BuiltInMeshUnbakedModelDeserializer.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/BuiltInMeshUnbakedModelDeserializer.java index da6aeda28ca..5abfd0853dd 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/BuiltInMeshUnbakedModelDeserializer.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/BuiltInMeshUnbakedModelDeserializer.java @@ -20,7 +20,7 @@ import com.google.gson.JsonObject; import org.jspecify.annotations.Nullable; -import net.minecraft.client.resources.model.UnbakedGeometry; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; import net.minecraft.util.GsonHelper; import net.fabricmc.fabric.api.client.renderer.v1.mesh.ShadeMode; diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameBlockStateModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameBlockStateModel.java index dfb0514b64c..2eb69c8ad61 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameBlockStateModel.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameBlockStateModel.java @@ -24,15 +24,16 @@ import org.jspecify.annotations.Nullable; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.model.BlockModelPart; -import net.minecraft.client.renderer.block.model.BlockStateModel; +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.chunk.ChunkSectionLayer; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.ModelBaker; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; @@ -59,7 +60,7 @@ public void emitQuads(QuadEmitter emitter, BlockAndTintGetter level, BlockPos po } BlockState innerState = mimickedBlock.defaultBlockState(); - BlockStateModel innerModel = Minecraft.getInstance().getBlockRenderer().getBlockModel(innerState); + BlockStateModel innerModel = Minecraft.getInstance().getModelManager().getBlockStateModelSet().get(innerState); // Now, we emit a transparent scaled-down version of the inner model @@ -110,7 +111,7 @@ public Object createGeometryKey(BlockAndTintGetter level, BlockPos pos, BlockSta } BlockState innerState = mimickedBlock.defaultBlockState(); - BlockStateModel innerModel = Minecraft.getInstance().getBlockRenderer().getBlockModel(innerState); + BlockStateModel innerModel = Minecraft.getInstance().getModelManager().getBlockStateModelSet().get(innerState); Object subkey = innerModel.createGeometryKey(level, pos, state, random); if (subkey == null) { @@ -124,25 +125,32 @@ record Key(Object subkey, boolean notEmissive) { } @Override - public void collectParts(RandomSource random, List parts) { + public void collectParts(RandomSource random, List parts) { // Renderer API makes this obsolete, so don't add any parts } @Override - public TextureAtlasSprite particleIcon() { - return frameModel.particleIcon(); + public Material.Baked particleMaterial() { + return frameModel.particleMaterial(); } @Override - public TextureAtlasSprite particleIcon(BlockAndTintGetter level, BlockPos pos, BlockState state) { + public @BakedQuad.MaterialFlags int materialFlags() { + // This model can render any submodel, which may be translucent and animated, so this model + // must report that it is also translucent and animated in the general case. + return BakedQuad.FLAG_ANIMATED | BakedQuad.FLAG_TRANSLUCENT; + } + + @Override + public Material.Baked particleMaterial(BlockAndTintGetter level, BlockPos pos, BlockState state) { // We should not access the block entity from here. We should instead use the immutable render data provided by the block entity. if (!(((FabricBlockGetter) level).getBlockEntityRenderData(pos) instanceof Block mimickedBlock)) { - return frameModel.particleIcon(level, pos, state); // No inner block to render, or data of wrong type + return frameModel.particleMaterial(level, pos, state); // No inner block to render, or data of wrong type } BlockState innerState = mimickedBlock.defaultBlockState(); - BlockStateModel innerModel = Minecraft.getInstance().getBlockRenderer().getBlockModel(innerState); - return innerModel.particleIcon(level, pos, state); + BlockStateModel innerModel = Minecraft.getInstance().getModelManager().getBlockStateModelSet().get(innerState); + return innerModel.particleMaterial(level, pos, state); } public record Unbaked(BlockStateModel.Unbaked frameModel) implements CustomUnbakedBlockStateModel { diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameGeometry.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameGeometry.java index 372d71c5372..fa9b444b666 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameGeometry.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameGeometry.java @@ -16,13 +16,15 @@ package net.fabricmc.fabric.test.renderer.client; -import net.minecraft.client.renderer.block.model.TextureSlots; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import java.util.Objects; + +import net.minecraft.client.renderer.block.dispatch.ModelState; import net.minecraft.client.resources.model.ModelBaker; import net.minecraft.client.resources.model.ModelDebugName; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.QuadCollection; -import net.minecraft.client.resources.model.UnbakedGeometry; +import net.minecraft.client.resources.model.geometry.QuadCollection; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.resources.model.sprite.Material; +import net.minecraft.client.resources.model.sprite.TextureSlots; import net.minecraft.core.Direction; import net.fabricmc.fabric.api.client.renderer.v1.Renderer; @@ -37,50 +39,51 @@ public record FrameGeometry(boolean emissive) implements UnbakedGeometry { public QuadCollection bake(TextureSlots textures, ModelBaker baker, ModelState settings, ModelDebugName model) { MutableMesh builder = Renderer.get().mutableMesh(); QuadEmitter emitter = builder.emitter(); - emitter.pushTransform(ModelStateHelper.asQuadTransform(settings, baker.sprites())); + emitter.pushTransform(ModelStateHelper.asQuadTransform(settings, baker.materials())); - TextureAtlasSprite sprite = baker.sprites().get(textures.getMaterial("frame"), model); + Material.Baked material = baker.materials() + .get(Objects.requireNonNull(textures.getMaterial("frame")), model); for (Direction direction : Direction.values()) { // Draw outer frame emitter.square(direction, 0.0F, 0.9F, 0.9F, 1.0F, 0.0F) - .spriteBake(sprite, MutableQuadView.BAKE_LOCK_UV) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) .emissive(emissive) .emit(); emitter.square(direction, 0.0F, 0.0F, 0.1F, 0.9F, 0.0F) - .spriteBake(sprite, MutableQuadView.BAKE_LOCK_UV) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) .emissive(emissive) .emit(); emitter.square(direction, 0.9F, 0.1F, 1.0F, 1.0F, 0.0F) - .spriteBake(sprite, MutableQuadView.BAKE_LOCK_UV) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) .emissive(emissive) .emit(); emitter.square(direction, 0.1F, 0.0F, 1.0F, 0.1F, 0.0F) - .spriteBake(sprite, MutableQuadView.BAKE_LOCK_UV) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) .emissive(emissive) .emit(); // Draw inner frame - inset by 0.9 so the frame looks like an actual mesh emitter.square(direction, 0.0F, 0.9F, 0.9F, 1.0F, 0.9F) - .spriteBake(sprite, MutableQuadView.BAKE_LOCK_UV) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) .emissive(emissive) .emit(); emitter.square(direction, 0.0F, 0.0F, 0.1F, 0.9F, 0.9F) - .spriteBake(sprite, MutableQuadView.BAKE_LOCK_UV) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) .emissive(emissive) .emit(); emitter.square(direction, 0.9F, 0.1F, 1.0F, 1.0F, 0.9F) - .spriteBake(sprite, MutableQuadView.BAKE_LOCK_UV) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) .emissive(emissive) .emit(); emitter.square(direction, 0.1F, 0.0F, 1.0F, 0.1F, 0.9F) - .spriteBake(sprite, MutableQuadView.BAKE_LOCK_UV) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) .emissive(emissive) .emit(); } diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OctagonalColumnGeometry.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OctagonalColumnGeometry.java index 5af456720d1..9d8b641c898 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OctagonalColumnGeometry.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OctagonalColumnGeometry.java @@ -16,14 +16,16 @@ package net.fabricmc.fabric.test.renderer.client; -import net.minecraft.client.renderer.block.model.TextureSlots; +import java.util.Objects; + +import net.minecraft.client.renderer.block.dispatch.ModelState; import net.minecraft.client.renderer.item.ItemStackRenderState; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.ModelBaker; import net.minecraft.client.resources.model.ModelDebugName; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.QuadCollection; -import net.minecraft.client.resources.model.UnbakedGeometry; +import net.minecraft.client.resources.model.geometry.QuadCollection; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.resources.model.sprite.Material; +import net.minecraft.client.resources.model.sprite.TextureSlots; import net.minecraft.core.Direction; import net.fabricmc.fabric.api.client.renderer.v1.Renderer; @@ -44,180 +46,181 @@ public record OctagonalColumnGeometry(ShadeMode shadeMode) implements UnbakedGeo public QuadCollection bake(TextureSlots textures, ModelBaker baker, ModelState settings, ModelDebugName model) { MutableMesh builder = Renderer.get().mutableMesh(); QuadEmitter emitter = builder.emitter(); - emitter.pushTransform(ModelStateHelper.asQuadTransform(settings, baker.sprites())); + emitter.pushTransform(ModelStateHelper.asQuadTransform(settings, baker.materials())); - TextureAtlasSprite sprite = baker.sprites().get(textures.getMaterial("column"), model); + Material.Baked material = baker.materials() + .get(Objects.requireNonNull(textures.getMaterial("column")), model); // up - emitter.pos(0, A, 1, 0); - 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(sprite, MutableQuadView.BAKE_LOCK_UV); - emitter.shadeMode(shadeMode); - emitter.emit(); - - emitter.pos(0, 0, 1, A); - 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(sprite, MutableQuadView.BAKE_LOCK_UV); - emitter.shadeMode(shadeMode); - emitter.emit(); - - emitter.pos(0, 0, 1, B); - 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(sprite, MutableQuadView.BAKE_LOCK_UV); - emitter.shadeMode(shadeMode); - emitter.emit(); - - emitter.pos(0, 0.5f, 1, 0.5f); - emitter.pos(1, B, 1, 1); - emitter.pos(2, 1, 1, B); - emitter.pos(3, 1, 1, A); - emitter.cullFace(Direction.UP); - emitter.spriteBake(sprite, MutableQuadView.BAKE_LOCK_UV); - emitter.shadeMode(shadeMode); - emitter.emit(); + emitter.pos(0, A, 1, 0) + .pos(1, 0.5f, 1, 0.5f) + .pos(2, 1, 1, A) + .pos(3, B, 1, 0) + .cullFace(Direction.UP) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) + .shadeMode(shadeMode) + .emit(); + + emitter.pos(0, 0, 1, A) + .pos(1, 0, 1, B) + .pos(2, 0.5f, 1, 0.5f) + .pos(3, A, 1, 0) + .cullFace(Direction.UP) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) + .shadeMode(shadeMode) + .emit(); + + emitter.pos(0, 0, 1, B) + .pos(1, A, 1, 1) + .pos(2, B, 1, 1) + .pos(3, 0.5f, 1, 0.5f) + .cullFace(Direction.UP) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) + .shadeMode(shadeMode) + .emit(); + + emitter.pos(0, 0.5f, 1, 0.5f) + .pos(1, B, 1, 1) + .pos(2, 1, 1, B) + .pos(3, 1, 1, A) + .cullFace(Direction.UP) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) + .shadeMode(shadeMode) + .emit(); // down - emitter.pos(0, A, 0, 1); - 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(sprite, MutableQuadView.BAKE_LOCK_UV); - emitter.shadeMode(shadeMode); - emitter.emit(); - - emitter.pos(0, 0, 0, B); - 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(sprite, MutableQuadView.BAKE_LOCK_UV); - emitter.shadeMode(shadeMode); - emitter.emit(); - - emitter.pos(0, 0, 0, A); - 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(sprite, MutableQuadView.BAKE_LOCK_UV); - emitter.shadeMode(shadeMode); - emitter.emit(); - - emitter.pos(0, 0.5f, 0, 0.5f); - emitter.pos(1, B, 0, 0); - emitter.pos(2, 1, 0, A); - emitter.pos(3, 1, 0, B); - emitter.cullFace(Direction.DOWN); - emitter.spriteBake(sprite, MutableQuadView.BAKE_LOCK_UV); - emitter.shadeMode(shadeMode); - emitter.emit(); + emitter.pos(0, A, 0, 1) + .pos(1, 0.5f, 0, 0.5f) + .pos(2, 1, 0, B) + .pos(3, B, 0, 1) + .cullFace(Direction.DOWN) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) + .shadeMode(shadeMode) + .emit(); + + emitter.pos(0, 0, 0, B) + .pos(1, 0, 0, A) + .pos(2, 0.5f, 0, 0.5f) + .pos(3, A, 0, 1) + .cullFace(Direction.DOWN) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) + .shadeMode(shadeMode) + .emit(); + + emitter.pos(0, 0, 0, A) + .pos(1, A, 0, 0) + .pos(2, B, 0, 0) + .pos(3, 0.5f, 0, 0.5f) + .cullFace(Direction.DOWN) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) + .shadeMode(shadeMode) + .emit(); + + emitter.pos(0, 0.5f, 0, 0.5f) + .pos(1, B, 0, 0) + .pos(2, 1, 0, A) + .pos(3, 1, 0, B) + .cullFace(Direction.DOWN) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) + .shadeMode(shadeMode) + .emit(); // north - emitter.pos(0, B, 1, 0); - emitter.pos(1, B, 0, 0); - emitter.pos(2, A, 0, 0); - emitter.pos(3, A, 1, 0); - emitter.cullFace(Direction.NORTH); - emitter.spriteBake(sprite, MutableQuadView.BAKE_LOCK_UV); - emitter.shadeMode(shadeMode); - emitter.foilType(ItemStackRenderState.FoilType.STANDARD); - emitter.emit(); + emitter.pos(0, B, 1, 0) + .pos(1, B, 0, 0) + .pos(2, A, 0, 0) + .pos(3, A, 1, 0) + .cullFace(Direction.NORTH) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) + .shadeMode(shadeMode) + .foilType(ItemStackRenderState.FoilType.STANDARD) + .emit(); // northwest - emitter.pos(0, A, 1, 0); - emitter.pos(1, A, 0, 0); - emitter.pos(2, 0, 0, A); - emitter.pos(3, 0, 1, A); - cornerSprite(emitter, sprite); - emitter.shadeMode(shadeMode); - emitter.foilType(ItemStackRenderState.FoilType.STANDARD); - emitter.emit(); + emitter.pos(0, A, 1, 0) + .pos(1, A, 0, 0) + .pos(2, 0, 0, A) + .pos(3, 0, 1, A); + cornerSprite(emitter, material); + emitter.shadeMode(shadeMode) + .foilType(ItemStackRenderState.FoilType.STANDARD) + .emit(); // west - emitter.pos(0, 0, 1, A); - emitter.pos(1, 0, 0, A); - emitter.pos(2, 0, 0, B); - emitter.pos(3, 0, 1, B); - emitter.cullFace(Direction.WEST); - emitter.spriteBake(sprite, MutableQuadView.BAKE_LOCK_UV); - emitter.shadeMode(shadeMode); - emitter.foilType(ItemStackRenderState.FoilType.STANDARD); - emitter.emit(); + emitter.pos(0, 0, 1, A) + .pos(1, 0, 0, A) + .pos(2, 0, 0, B) + .pos(3, 0, 1, B) + .cullFace(Direction.WEST) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) + .shadeMode(shadeMode) + .foilType(ItemStackRenderState.FoilType.STANDARD) + .emit(); // southwest - emitter.pos(0, 0, 1, B); - emitter.pos(1, 0, 0, B); - emitter.pos(2, A, 0, 1); - emitter.pos(3, A, 1, 1); - cornerSprite(emitter, sprite); - emitter.shadeMode(shadeMode); - emitter.foilType(ItemStackRenderState.FoilType.STANDARD); - emitter.emit(); + emitter.pos(0, 0, 1, B) + .pos(1, 0, 0, B) + .pos(2, A, 0, 1) + .pos(3, A, 1, 1); + cornerSprite(emitter, material); + emitter.shadeMode(shadeMode) + .foilType(ItemStackRenderState.FoilType.STANDARD) + .emit(); // south - emitter.pos(0, A, 1, 1); - emitter.pos(1, A, 0, 1); - emitter.pos(2, B, 0, 1); - emitter.pos(3, B, 1, 1); - emitter.cullFace(Direction.SOUTH); - emitter.spriteBake(sprite, MutableQuadView.BAKE_LOCK_UV); - emitter.shadeMode(shadeMode); - emitter.foilType(ItemStackRenderState.FoilType.STANDARD); - emitter.emit(); + emitter.pos(0, A, 1, 1) + .pos(1, A, 0, 1) + .pos(2, B, 0, 1) + .pos(3, B, 1, 1) + .cullFace(Direction.SOUTH) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) + .shadeMode(shadeMode) + .foilType(ItemStackRenderState.FoilType.STANDARD) + .emit(); // southeast - emitter.pos(0, B, 1, 1); - emitter.pos(1, B, 0, 1); - emitter.pos(2, 1, 0, B); - emitter.pos(3, 1, 1, B); - cornerSprite(emitter, sprite); - emitter.shadeMode(shadeMode); - emitter.foilType(ItemStackRenderState.FoilType.STANDARD); - emitter.emit(); + emitter.pos(0, B, 1, 1) + .pos(1, B, 0, 1) + .pos(2, 1, 0, B) + .pos(3, 1, 1, B); + cornerSprite(emitter, material); + emitter.shadeMode(shadeMode) + .foilType(ItemStackRenderState.FoilType.STANDARD) + .emit(); // east - emitter.pos(0, 1, 1, B); - emitter.pos(1, 1, 0, B); - emitter.pos(2, 1, 0, A); - emitter.pos(3, 1, 1, A); - emitter.cullFace(Direction.EAST); - emitter.spriteBake(sprite, MutableQuadView.BAKE_LOCK_UV); - emitter.shadeMode(shadeMode); - emitter.foilType(ItemStackRenderState.FoilType.STANDARD); - emitter.emit(); + emitter.pos(0, 1, 1, B) + .pos(1, 1, 0, B) + .pos(2, 1, 0, A) + .pos(3, 1, 1, A) + .cullFace(Direction.EAST) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) + .shadeMode(shadeMode) + .foilType(ItemStackRenderState.FoilType.STANDARD) + .emit(); // northeast - emitter.pos(0, 1, 1, A); - emitter.pos(1, 1, 0, A); - emitter.pos(2, B, 0, 0); - emitter.pos(3, B, 1, 0); - cornerSprite(emitter, sprite); - emitter.shadeMode(shadeMode); - emitter.foilType(ItemStackRenderState.FoilType.STANDARD); - emitter.emit(); + emitter.pos(0, 1, 1, A) + .pos(1, 1, 0, A) + .pos(2, B, 0, 0) + .pos(3, B, 1, 0); + cornerSprite(emitter, material); + emitter.shadeMode(shadeMode) + .foilType(ItemStackRenderState.FoilType.STANDARD) + .emit(); return new MeshQuadCollection(builder.immutableCopy()); } - private static void cornerSprite(QuadEmitter emitter, TextureAtlasSprite sprite) { + private static void cornerSprite(QuadEmitter emitter, Material.Baked material) { // 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); + emitter.uv(0, A, 0) + .uv(1, A, 1) + .uv(2, B, 1) + .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); + emitter.materialBake(material, MutableQuadView.BAKE_NORMALIZED); } } diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OverlayedGeometry.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OverlayedGeometry.java index 1e3f2b8a263..bed9f58a3db 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OverlayedGeometry.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OverlayedGeometry.java @@ -16,21 +16,24 @@ package net.fabricmc.fabric.test.renderer.client; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.block.model.TextureSlots; +import java.util.Objects; + +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.ModelDebugName; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.QuadCollection; import net.minecraft.client.resources.model.ResolvedModel; -import net.minecraft.client.resources.model.UnbakedGeometry; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.geometry.QuadCollection; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.resources.model.sprite.Material; +import net.minecraft.client.resources.model.sprite.TextureSlots; import net.minecraft.core.Direction; import net.minecraft.resources.Identifier; -import net.minecraft.util.Mth; import net.fabricmc.fabric.api.client.renderer.v1.Renderer; 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.QuadAtlas; import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter; import net.fabricmc.fabric.api.client.renderer.v1.model.MeshQuadCollection; @@ -44,8 +47,10 @@ public QuadCollection bake(TextureSlots textures, ModelBaker modelBaker, ModelSt ResolvedModel parentModel = modelBaker.getModel(parentId); QuadCollection parentQuads = parentModel.bakeTopGeometry(parentModel.getTopTextureSlots(), modelBaker, modelState); - TextureAtlasSprite overlaySprite = modelBaker.sprites().get(textures.getMaterial("overlay"), name); - QuadAtlas overlayAtlas = QuadAtlas.of(overlaySprite.atlasLocation()); + Material.Baked overlayMaterial = modelBaker.materials() + .get(Objects.requireNonNull(textures.getMaterial("overlay")), name); + TextureAtlasSprite overlaySprite = overlayMaterial.sprite(); + QuadAtlas overlayAtlas = QuadAtlas.ofLocation(overlaySprite.atlasLocation()); if (overlayAtlas == null) { return parentQuads; @@ -55,18 +60,7 @@ public QuadCollection bake(TextureSlots textures, ModelBaker modelBaker, ModelSt meshQuadCollection.getMesh().forEach(quad -> { emitter.copyFrom(quad).emit(); emitter.copyFrom(quad); - emitter.atlas(overlayAtlas); - - TextureAtlasSprite sprite = modelBaker.sprites().spriteFinder(emitter.atlas()).find(emitter); - - for (int i = 0; i < 4; i++) { - emitter.uv( - i, - overlaySprite.getU(Mth.inverseLerp(emitter.u(i), sprite.getU0(), sprite.getU1())), - overlaySprite.getV(Mth.inverseLerp(emitter.v(i), sprite.getV0(), sprite.getV1())) - ); - } - + emitter.materialBake(overlayMaterial, MutableQuadView.BAKE_LOCK_UV); emitter.emit(); }); } else { @@ -76,18 +70,7 @@ public QuadCollection bake(TextureSlots textures, ModelBaker modelBaker, ModelSt for (BakedQuad bakedQuad : parentQuads.getQuads(cullFace)) { emitter.fromBakedQuad(bakedQuad).cullFace(cullFace).emit(); emitter.fromBakedQuad(bakedQuad).cullFace(cullFace); - emitter.atlas(overlayAtlas); - - TextureAtlasSprite sprite = bakedQuad.sprite(); - - for (int j = 0; j < 4; j++) { - emitter.uv( - j, - overlaySprite.getU(Mth.inverseLerp(emitter.u(j), sprite.getU0(), sprite.getU1())), - overlaySprite.getV(Mth.inverseLerp(emitter.v(j), sprite.getV0(), sprite.getV1())) - ); - } - + emitter.materialBake(overlayMaterial, MutableQuadView.BAKE_LOCK_UV); emitter.emit(); } } diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OverlayedUnbakedModelDeserializer.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OverlayedUnbakedModelDeserializer.java index de89d957ffc..249e7b2e7c2 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OverlayedUnbakedModelDeserializer.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OverlayedUnbakedModelDeserializer.java @@ -20,7 +20,7 @@ import com.google.gson.JsonObject; import org.jspecify.annotations.Nullable; -import net.minecraft.client.resources.model.UnbakedGeometry; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; import net.minecraft.resources.Identifier; public class OverlayedUnbakedModelDeserializer extends SimpleUnbakedModelDeserializer { diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarBlockStateModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarBlockStateModel.java index 3314a0382bb..23eb6395519 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarBlockStateModel.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarBlockStateModel.java @@ -23,17 +23,16 @@ import com.mojang.serialization.MapCodec; import org.jspecify.annotations.Nullable; -import net.minecraft.client.renderer.block.model.BlockModelPart; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.texture.TextureAtlas; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.Material; +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.resources.model.ModelBaker; import net.minecraft.client.resources.model.ModelDebugName; +import net.minecraft.client.resources.model.geometry.BakedQuad; +import net.minecraft.client.resources.model.sprite.Material; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; import net.fabricmc.fabric.api.block.v1.FabricBlockState; @@ -52,19 +51,43 @@ private enum ConnectedTexture { } // alone, bottom, middle, top - private final TextureAtlasSprite[] sprites; + private final Material.Baked[] materials; + private final @BakedQuad.MaterialFlags int materialFlags; - public PillarBlockStateModel(TextureAtlasSprite[] sprites) { - this.sprites = sprites; + public PillarBlockStateModel(Material.Baked[] materials) { + this.materials = materials; + + boolean translucent = false; + boolean animated = false; + + for (Material.Baked material : materials) { + translucent = translucent || material.forceTranslucent() || material.sprite() + .contents() + .computeTransparency(0.0f, 0.0f, 1.0f, 1.0f) + .hasTranslucent(); + animated = animated || material.sprite().contents().isAnimated(); + } + + @BakedQuad.MaterialFlags int materialFlags = 0; + + if (translucent) { + materialFlags |= BakedQuad.FLAG_TRANSLUCENT; + } + + if (animated) { + materialFlags |= BakedQuad.FLAG_ANIMATED; + } + + this.materialFlags = materialFlags; } @Override public void emitQuads(QuadEmitter emitter, BlockAndTintGetter level, BlockPos pos, BlockState state, RandomSource random, Predicate<@Nullable Direction> cullTest) { for (Direction side : Direction.values()) { ConnectedTexture texture = getConnectedTexture(level, pos, state, side); - emitter.square(side, 0, 0, 1, 1, 0); - emitter.spriteBake(sprites[texture.ordinal()], MutableQuadView.BAKE_LOCK_UV); - emitter.emit(); + emitter.square(side, 0, 0, 1, 1, 0) + .materialBake(materials[texture.ordinal()], MutableQuadView.BAKE_LOCK_UV) + .emit(); } } @@ -111,25 +134,26 @@ private static boolean canConnect(BlockAndTintGetter level, BlockState originSta BlockState otherAppearance = ((FabricBlockState) otherState).getAppearance( level, otherPos, side, originState, originPos); - if (!otherAppearance.is(Registration.PILLAR_BLOCK)) { - return false; - } + return otherAppearance.is(Registration.PILLAR_BLOCK); + } - return true; + @Override + public void collectParts(RandomSource random, List parts) { } @Override - public void collectParts(RandomSource random, List parts) { + public Material.Baked particleMaterial() { + return materials[0]; } @Override - public TextureAtlasSprite particleIcon() { - return sprites[0]; + public @BakedQuad.MaterialFlags int materialFlags() { + return materialFlags; } public record Unbaked() implements CustomUnbakedBlockStateModel, ModelDebugName { - private static final List SPRITES = Stream.of("alone", "bottom", "middle", "top") - .map(suffix -> new Material(TextureAtlas.LOCATION_BLOCKS, RendererTest.id("block/pillar_" + suffix))) + private static final List MATERIALS = Stream.of("alone", "bottom", "middle", "top") + .map(suffix -> new Material(RendererTest.id("block/pillar_" + suffix))) .toList(); public static final Unbaked INSTANCE = new Unbaked(); public static final MapCodec CODEC = MapCodec.unit(INSTANCE); @@ -145,13 +169,15 @@ public void resolveDependencies(Resolver resolver) { @Override public BlockStateModel bake(ModelBaker baker) { - TextureAtlasSprite[] sprites = new TextureAtlasSprite[SPRITES.size()]; + Material.Baked[] materials = new Material.Baked[MATERIALS.size()]; - for (int i = 0; i < sprites.length; ++i) { - sprites[i] = baker.sprites().get(SPRITES.get(i), this); + for (int i = 0; i < materials.length; ++i) { + Material.Baked material = baker.materials() + .get(MATERIALS.get(i), this); + materials[i] = material; } - return new PillarBlockStateModel(sprites); + return new PillarBlockStateModel(materials); } @Override diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarGeometry.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarGeometry.java index eb4d12ec3d1..3866877e638 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarGeometry.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarGeometry.java @@ -16,13 +16,15 @@ package net.fabricmc.fabric.test.renderer.client; -import net.minecraft.client.renderer.block.model.TextureSlots; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import java.util.Objects; + +import net.minecraft.client.renderer.block.dispatch.ModelState; import net.minecraft.client.resources.model.ModelBaker; import net.minecraft.client.resources.model.ModelDebugName; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.QuadCollection; -import net.minecraft.client.resources.model.UnbakedGeometry; +import net.minecraft.client.resources.model.geometry.QuadCollection; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.resources.model.sprite.Material; +import net.minecraft.client.resources.model.sprite.TextureSlots; import net.minecraft.core.Direction; import net.fabricmc.fabric.api.client.renderer.v1.Renderer; @@ -37,14 +39,15 @@ public record PillarGeometry() implements UnbakedGeometry { public QuadCollection bake(TextureSlots textures, ModelBaker baker, ModelState settings, ModelDebugName model) { MutableMesh builder = Renderer.get().mutableMesh(); QuadEmitter emitter = builder.emitter(); - emitter.pushTransform(ModelStateHelper.asQuadTransform(settings, baker.sprites())); + emitter.pushTransform(ModelStateHelper.asQuadTransform(settings, baker.materials())); - TextureAtlasSprite sprite = baker.sprites().get(textures.getMaterial("pillar"), model); + Material.Baked material = baker.materials() + .get(Objects.requireNonNull(textures.getMaterial("pillar")), model); for (Direction side : Direction.values()) { - emitter.square(side, 0, 0, 1, 1, 0); - emitter.spriteBake(sprite, MutableQuadView.BAKE_LOCK_UV); - emitter.emit(); + emitter.square(side, 0, 0, 1, 1, 0) + .materialBake(material, MutableQuadView.BAKE_LOCK_UV) + .emit(); } return new MeshQuadCollection(builder.immutableCopy()); diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/RendererClientTest.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/RendererClientTest.java index 5f2406a6935..5b984d57220 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/RendererClientTest.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/RendererClientTest.java @@ -16,14 +16,10 @@ package net.fabricmc.fabric.test.renderer.client; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; - import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.model.loading.v1.CustomUnbakedBlockStateModel; import net.fabricmc.fabric.api.client.model.loading.v1.UnbakedModelDeserializer; import net.fabricmc.fabric.api.client.renderer.v1.Renderer; -import net.fabricmc.fabric.api.client.rendering.v1.ChunkSectionLayerMap; -import net.fabricmc.fabric.test.renderer.Registration; import net.fabricmc.fabric.test.renderer.RendererTest; public final class RendererClientTest implements ClientModInitializer { @@ -36,10 +32,6 @@ public void onInitializeClient() { CustomUnbakedBlockStateModel.register(RendererTest.id("frame"), FrameBlockStateModel.Unbaked.CODEC); CustomUnbakedBlockStateModel.register(RendererTest.id("pillar"), PillarBlockStateModel.Unbaked.CODEC); - // We don't specify a material for the frame mesh, - // so it will use the default material, i.e. the one from ChunkSectionLayers. - ChunkSectionLayerMap.putBlock(Registration.FRAME_BLOCK, ChunkSectionLayer.CUTOUT); - try { // if it crashes, that means the ordering is #*@!ed up. Renderer.get(); // Ensure Renderer can be initialized as early as mod init diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/SimpleUnbakedModelDeserializer.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/SimpleUnbakedModelDeserializer.java index 40371efbdf9..890a616b992 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/SimpleUnbakedModelDeserializer.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/SimpleUnbakedModelDeserializer.java @@ -24,13 +24,13 @@ import com.google.gson.JsonObject; import org.jspecify.annotations.Nullable; -import net.minecraft.client.renderer.block.model.BlockElement; -import net.minecraft.client.renderer.block.model.BlockModel; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.renderer.block.model.SimpleUnbakedGeometry; -import net.minecraft.client.renderer.block.model.TextureSlots; -import net.minecraft.client.resources.model.UnbakedGeometry; import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.client.resources.model.cuboid.CuboidModel; +import net.minecraft.client.resources.model.cuboid.CuboidModelElement; +import net.minecraft.client.resources.model.cuboid.ItemTransforms; +import net.minecraft.client.resources.model.cuboid.UnbakedCuboidGeometry; +import net.minecraft.client.resources.model.geometry.UnbakedGeometry; +import net.minecraft.client.resources.model.sprite.TextureSlots; import net.minecraft.resources.Identifier; import net.minecraft.util.GsonHelper; @@ -58,20 +58,20 @@ public UnbakedModel deserialize(JsonObject json, JsonDeserializationContext cont TextureSlots.Data textureMap = getTextureMap(object); Identifier parentLocation = getParentLocation(object); - return new BlockModel(elements, guiLight, hasAmbientOcclusion, transforms, textureMap, parentLocation); + return new CuboidModel(elements, guiLight, hasAmbientOcclusion, transforms, textureMap, parentLocation); } protected @Nullable UnbakedGeometry getElements(final JsonDeserializationContext context, final JsonObject object) { if (!object.has("elements")) { return null; } else { - List elements = new ArrayList<>(); + List elements = new ArrayList<>(); for (JsonElement element : GsonHelper.getAsJsonArray(object, "elements")) { - elements.add(context.deserialize(element, BlockElement.class)); + elements.add(context.deserialize(element, CuboidModelElement.class)); } - return new SimpleUnbakedGeometry(elements); + return new UnbakedCuboidGeometry(elements); } } 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 98d7ff8f91f..edf3f279274 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,6 +28,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import net.minecraft.client.renderer.MultiBufferSource; + import net.fabricmc.fabric.api.util.TriState; import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.AoConfig; import net.fabricmc.loader.api.FabricLoader; @@ -46,6 +48,9 @@ public class Indigo { /** 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); } @@ -90,12 +95,12 @@ private static TriState asTriState(@Nullable String property) { } } - AMBIENT_OCCLUSION_MODE = asEnum((String) properties.computeIfAbsent("ambient-occlusion-mode", (_) -> "hybrid"), AoConfig.HYBRID); - DEBUG_COMPARE_LIGHTING = asBoolean((String) properties.computeIfAbsent("debug-compare-lighting", (_) -> "auto"), false); - FIX_SMOOTH_LIGHTING_OFFSET = asBoolean((String) properties.computeIfAbsent("fix-smooth-lighting-offset", (_) -> "auto"), true); - boolean fixMeanLightCalculation = asBoolean((String) properties.computeIfAbsent("fix-mean-light-calculation", (_) -> "auto"), true); - FIX_EXTERIOR_VERTEX_LIGHTING = asBoolean((String) properties.computeIfAbsent("fix-exterior-vertex-lighting", (_) -> "auto"), true); - FIX_LUMINOUS_AO_SHADE = asBoolean((String) properties.computeIfAbsent("fix-luminous-block-ambient-occlusion", (_) -> "auto"), false); + AMBIENT_OCCLUSION_MODE = asEnum((String) properties.computeIfAbsent("ambient-occlusion-mode", _ -> "hybrid"), AoConfig.HYBRID); + DEBUG_COMPARE_LIGHTING = asBoolean((String) properties.computeIfAbsent("debug-compare-lighting", _ -> "auto"), false); + FIX_SMOOTH_LIGHTING_OFFSET = asBoolean((String) properties.computeIfAbsent("fix-smooth-lighting-offset", _ -> "auto"), true); + boolean fixMeanLightCalculation = asBoolean((String) properties.computeIfAbsent("fix-mean-light-calculation", _ -> "auto"), true); + FIX_EXTERIOR_VERTEX_LIGHTING = asBoolean((String) properties.computeIfAbsent("fix-exterior-vertex-lighting", _ -> "auto"), true); + FIX_LUMINOUS_AO_SHADE = asBoolean((String) properties.computeIfAbsent("fix-luminous-block-ambient-occlusion", _ -> "auto"), false); if (fixMeanLightCalculation && !FIX_SMOOTH_LIGHTING_OFFSET) { fixMeanLightCalculation = false; diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/IndigoRenderer.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/IndigoRenderer.java index f26b7e0f5a9..d035dc0c9e4 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/IndigoRenderer.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/IndigoRenderer.java @@ -16,34 +16,19 @@ package net.fabricmc.fabric.impl.client.indigo.renderer; -import java.util.function.Predicate; +import java.util.function.Consumer; -import com.mojang.blaze3d.vertex.PoseStack; -import org.jspecify.annotations.Nullable; - -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.block.BlockRenderDispatcher; -import net.minecraft.client.renderer.block.ModelBlockRenderer; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; -import net.minecraft.client.renderer.item.ItemStackRenderState; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.RenderShape; -import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.client.color.block.BlockColors; import net.fabricmc.fabric.api.client.renderer.v1.Renderer; 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.BlockMultiBufferSource; -import net.fabricmc.fabric.api.client.renderer.v1.render.ChunkSectionLayerHelper; -import net.fabricmc.fabric.api.client.renderer.v1.render.FabricModelBlockRenderer; -import net.fabricmc.fabric.api.client.renderer.v1.render.ItemRenderTypeGetter; -import net.fabricmc.fabric.impl.client.indigo.renderer.accessor.AccessLayerRenderState; +import net.fabricmc.fabric.api.client.renderer.v1.render.AltModelBlockRenderer; +import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.EncodingFormat; import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableMeshImpl; -import net.fabricmc.fabric.impl.client.indigo.renderer.render.SimpleBlockRenderContext; -import net.fabricmc.fabric.impl.client.indigo.renderer.render.TerrainLikeRenderContext; -import net.fabricmc.fabric.mixin.client.indigo.renderer.BlockRenderDispatcherAccessor; +import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl; +import net.fabricmc.fabric.impl.client.indigo.renderer.render.AltModelBlockRendererImpl; /** * The Fabric default renderer implementation. Supports all features defined in the API. @@ -63,49 +48,27 @@ static IndigoRenderer getOrCreateInstance() { } @Override - public MutableMesh mutableMesh() { - return new MutableMeshImpl(); - } - - @Override - public void tesselateBlock(ModelBlockRenderer blockRenderer, BlockAndTintGetter level, BlockStateModel model, BlockState state, BlockPos pos, PoseStack poseStack, BlockMultiBufferSource bufferSource, @Nullable Predicate layerFilter, boolean cull, long seed, int overlay) { - TerrainLikeRenderContext.POOL.get().bufferModel( - level, model, state, pos, poseStack, bufferSource, layerFilter, cull, seed, overlay); - } - - @Override - public void renderModel(PoseStack.Pose pose, BlockMultiBufferSource bufferSource, @Nullable Predicate layerFilter, BlockStateModel model, float red, float green, float blue, int light, int overlay, BlockAndTintGetter level, BlockPos pos, BlockState state) { - SimpleBlockRenderContext.POOL.get().bufferModel( - pose, bufferSource, layerFilter, model, red, green, blue, light, overlay, level, pos, state); - } - - @Override - public void renderSingleBlock(BlockRenderDispatcher renderDispatcher, BlockState state, PoseStack poseStack, MultiBufferSource bufferSource, @Nullable Predicate layerFilter, int light, int overlay, BlockAndTintGetter level, BlockPos pos) { - RenderShape renderShape = state.getRenderShape(); - - if (renderShape != RenderShape.INVISIBLE) { - BlockStateModel model = renderDispatcher.getBlockModel(state); - int tint = ((BlockRenderDispatcherAccessor) renderDispatcher).getBlockColors().getColor(state, null, null, 0); - float red = (tint >> 16 & 255) / 255.0F; - float green = (tint >> 8 & 255) / 255.0F; - float blue = (tint & 255) / 255.0F; - FabricModelBlockRenderer.renderModel( - poseStack.last(), ChunkSectionLayerHelper.entityDelegate( - bufferSource), layerFilter, model, red, green, blue, light, overlay, - level, pos, state); - } + public QuadEmitter quadEmitter(Consumer consumer) { + return new MutableQuadViewImpl() { + { + data = new int[EncodingFormat.TOTAL_STRIDE]; + clear(); + } + + @Override + protected void emitDirectly() { + consumer.accept(this); + } + }; } @Override - public QuadEmitter getLayerRenderStateEmitter(ItemStackRenderState.LayerRenderState layer) { - return ((AccessLayerRenderState) layer).fabric_getMutableMesh().emitter(); + public MutableMesh mutableMesh() { + return new MutableMeshImpl(); } @Override - public void setLayerRenderTypeGetter( - ItemStackRenderState.LayerRenderState layer, - ItemRenderTypeGetter renderTypeGetter - ) { - ((AccessLayerRenderState) layer).fabric_setRenderTypeGetter(renderTypeGetter); + public AltModelBlockRenderer altModelBlockRenderer(boolean ambientOcclusion, boolean cull, BlockColors blockColors) { + return new AltModelBlockRendererImpl(ambientOcclusion, cull, blockColors); } } diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/accessor/AccessLayerRenderState.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/accessor/AccessLayerRenderState.java deleted file mode 100644 index 82bc5498cc3..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/accessor/AccessLayerRenderState.java +++ /dev/null @@ -1,26 +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.accessor; - -import net.fabricmc.fabric.api.client.renderer.v1.render.ItemRenderTypeGetter; -import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableMeshImpl; - -public interface AccessLayerRenderState { - MutableMeshImpl fabric_getMutableMesh(); - - void fabric_setRenderTypeGetter(ItemRenderTypeGetter renderTypeGetter); -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/accessor/AccessOrderedSubmitNodeCollector.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/accessor/AccessOrderedSubmitNodeCollector.java deleted file mode 100644 index 8080030a737..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/accessor/AccessOrderedSubmitNodeCollector.java +++ /dev/null @@ -1,46 +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.accessor; - -import java.util.List; - -import com.mojang.blaze3d.vertex.PoseStack; -import org.jspecify.annotations.Nullable; - -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.item.ItemStackRenderState; -import net.minecraft.client.renderer.rendertype.RenderType; -import net.minecraft.world.item.ItemDisplayContext; - -import net.fabricmc.fabric.api.client.renderer.v1.mesh.MeshView; -import net.fabricmc.fabric.api.client.renderer.v1.render.ItemRenderTypeGetter; - -public interface AccessOrderedSubmitNodeCollector { - void fabric_submitItem( - PoseStack poseStack, - ItemDisplayContext displayContext, - int light, - int overlay, - int outlineColors, - int[] tintLayers, - List quads, - RenderType renderType, - ItemStackRenderState.FoilType foilType, - MeshView mesh, - @Nullable ItemRenderTypeGetter renderTypeGetter - ); -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/accessor/AccessRenderSectionRegion.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/accessor/AccessRenderSectionRegion.java deleted file mode 100644 index c77121d4c0a..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/accessor/AccessRenderSectionRegion.java +++ /dev/null @@ -1,29 +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.accessor; - -import net.fabricmc.fabric.impl.client.indigo.renderer.render.TerrainRenderContext; - -/** - * Used to stash block renderer reference in local scope during - * chunk rebuild, thus avoiding repeated thread-local lookups. - */ -public interface AccessRenderSectionRegion { - TerrainRenderContext fabric_getRenderer(); - - void fabric_setRenderer(TerrainRenderContext renderer); -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/accessor/AccessSubmitNodeCollection.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/accessor/AccessSubmitNodeCollection.java deleted file mode 100644 index 50d89b2354a..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/accessor/AccessSubmitNodeCollection.java +++ /dev/null @@ -1,25 +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.accessor; - -import java.util.List; - -import net.fabricmc.fabric.impl.client.indigo.renderer.render.MeshItemSubmit; - -public interface AccessSubmitNodeCollection { - List fabric_getMeshItemSubmits(); -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/aocalc/AoCalculator.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/aocalc/AoCalculator.java index 96d5f0c93f0..ff0a3bf7329 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/aocalc/AoCalculator.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/aocalc/AoCalculator.java @@ -20,37 +20,42 @@ import static net.fabricmc.fabric.impl.client.indigo.renderer.helper.GeometryHelper.CUBIC_FLAG; import static net.fabricmc.fabric.impl.client.indigo.renderer.helper.GeometryHelper.LIGHT_FACE_FLAG; +import com.mojang.blaze3d.vertex.QuadInstance; import org.joml.Vector3f; import org.joml.Vector3fc; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import net.minecraft.client.renderer.block.ModelBlockRenderer; -import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.Sheets; +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.BlockModelLighter; +import net.minecraft.client.renderer.chunk.ChunkSectionLayer; +import net.minecraft.client.resources.model.geometry.BakedQuad; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.util.ARGB; import net.minecraft.util.Mth; -import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; import net.fabricmc.fabric.impl.client.indigo.Indigo; import net.fabricmc.fabric.impl.client.indigo.renderer.helper.GeometryHelper; import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.QuadViewImpl; -import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderInfo; -import net.fabricmc.fabric.impl.client.indigo.renderer.render.LightDataProvider; /** - * Adaptation of inner, non-static class in ModelBlockRenderer that serves same purpose. + * Adaptation of BlockModelLighter that serves same purpose. */ public class AoCalculator { private static final Logger LOGGER = LoggerFactory.getLogger(AoCalculator.class); - private final BlockRenderInfo blockInfo; - private final LightDataProvider dataProvider; + private final BlockModelLighter.Cache lightCache; private final BlockPos.MutableBlockPos lightPos = new BlockPos.MutableBlockPos(); private final BlockPos.MutableBlockPos searchPos = new BlockPos.MutableBlockPos(); + private BlockAndTintGetter level; + private BlockState state; + private BlockPos pos; + /** caches results of {@link #computeFace(Direction, boolean, boolean)} for the current block. */ private final AoFaceData[] faceData = new AoFaceData[24]; @@ -64,9 +69,8 @@ public class AoCalculator { public final float[] ao = new float[4]; public final int[] light = new int[4]; - public AoCalculator(BlockRenderInfo blockInfo, LightDataProvider dataProvider) { - this.blockInfo = blockInfo; - this.dataProvider = dataProvider; + public AoCalculator(BlockModelLighter.Cache lightCache) { + this.lightCache = lightCache; for (int i = 0; i < 24; i++) { faceData[i] = new AoFaceData(); @@ -74,10 +78,17 @@ public AoCalculator(BlockRenderInfo blockInfo, LightDataProvider dataProvider) { } /** call at start of each new block. */ - public void clear() { + public void prepare(BlockAndTintGetter level, BlockState state, BlockPos pos) { + this.level = level; + this.state = state; + this.pos = pos; completionFlags = 0; } + public void clear() { + level = null; + } + public void compute(QuadViewImpl quad, boolean vanillaShade) { final AoConfig config = Indigo.AMBIENT_OCCLUSION_MODE; @@ -101,7 +112,7 @@ public void compute(QuadViewImpl quad, boolean vanillaShade) { for (int i = 0; i < 4; i++) { if (light[i] != vanillaLight[i] || !Mth.equal(ao[i], vanillaAo[i])) { - LOGGER.info(String.format("Mismatch for %s @ %s", blockInfo.blockState.toString(), blockInfo.blockPos.toString())); + LOGGER.info(String.format("Mismatch for %s @ %s", state.toString(), pos.toString())); LOGGER.info(String.format("Flags = %d, LightFace = %s", quad.geometryFlags(), quad.lightFace().toString())); LOGGER.info(String.format(" Old Brightness: %.2f, %.2f, %.2f, %.2f", vanillaAo[0], vanillaAo[1], vanillaAo[2], vanillaAo[3])); LOGGER.info(String.format(" New Brightness: %.2f, %.2f, %.2f, %.2f", ao[0], ao[1], ao[2], ao[3])); @@ -120,11 +131,13 @@ private void calcVanilla(QuadViewImpl quad) { // These are what vanilla AO calc wants, per its usage in vanilla code // Because this instance is effectively thread-local, we preserve instances // to avoid making a new allocation each call. - private final ModelBlockRenderer.AmbientOcclusionRenderStorage vanillaCalc = new ModelBlockRenderer.AmbientOcclusionRenderStorage(); + private final BlockModelLighter vanillaCalc = new BlockModelLighter(); + private final QuadInstance vanillaQuadInstance = new QuadInstance(); private final Vector3f vanillaPos0 = new Vector3f(); private final Vector3f vanillaPos1 = new Vector3f(); private final Vector3f vanillaPos2 = new Vector3f(); private final Vector3f vanillaPos3 = new Vector3f(); + private final BakedQuad.MaterialInfo vanillaMaterialInfo = new BakedQuad.MaterialInfo(null, ChunkSectionLayer.SOLID, Sheets.cutoutBlockItemSheet(), -1, true, 0); private void calcVanilla(QuadViewImpl quad, float[] aoDest, int[] lightDest) { // calculateShape only uses the vertex positions and light face of the quad, so making a new BakedQuad every @@ -136,14 +149,18 @@ private void calcVanilla(QuadViewImpl quad, float[] aoDest, int[] lightDest) { quad.copyPos(1, vanillaPos1), quad.copyPos(2, vanillaPos2), quad.copyPos(3, vanillaPos3), - 0, 0, 0, 0, -1, quad.lightFace(), null, true, 0 + 0, 0, 0, 0, + quad.lightFace(), + vanillaMaterialInfo ); - ModelBlockRenderer.calculateShape(blockInfo.level, blockInfo.blockState, blockInfo.blockPos, bakedQuad, vanillaCalc); - vanillaCalc.calculate(blockInfo.level, blockInfo.blockState, blockInfo.blockPos, quad.lightFace(), quad.diffuseShade()); + vanillaCalc.prepareQuadAmbientOcclusion(level, state, pos, bakedQuad, vanillaQuadInstance); - System.arraycopy(vanillaCalc.brightness, 0, aoDest, 0, 4); - System.arraycopy(vanillaCalc.lightmap, 0, lightDest, 0, 4); + for (int i = 0; i < 4; i++) { + // the color is expected to be fully gray, so we can pick either one and be fine. + aoDest[i] = ARGB.redFloat(vanillaQuadInstance.getColor(i)); + lightDest[i] = vanillaQuadInstance.getLightCoords(i); + } } private void calcFastVanilla(QuadViewImpl quad) { @@ -151,7 +168,7 @@ private void calcFastVanilla(QuadViewImpl quad) { boolean isOnLightFace = (flags & LIGHT_FACE_FLAG) != 0; // force to block face if shape is full cube - matches vanilla logic - if (!isOnLightFace && (flags & AXIS_ALIGNED_FLAG) != 0 && blockInfo.blockState.isCollisionShapeFullBlock(blockInfo.level, blockInfo.blockPos)) { + if (!isOnLightFace && (flags & AXIS_ALIGNED_FLAG) != 0 && state.isCollisionShapeFullBlock(level, pos)) { isOnLightFace = true; } @@ -340,9 +357,9 @@ private AoFaceData computeFace(Direction lightFace, boolean isOnBlockFace, boole * Except for parameterization, the logic itself is practically identical to vanilla. */ private void computeFace(AoFaceData result, Direction lightFace, boolean isOnBlockFace, boolean shade) { - final BlockAndTintGetter level = blockInfo.level; - final BlockPos pos = blockInfo.blockPos; - final BlockState blockState = blockInfo.blockState; + final BlockAndTintGetter level = this.level; + final BlockPos pos = this.pos; + final BlockState blockState = this.state; final BlockPos.MutableBlockPos lightPos = this.lightPos; final BlockPos.MutableBlockPos searchPos = this.searchPos; BlockState searchState; @@ -361,51 +378,51 @@ private void computeFace(AoFaceData result, Direction lightFace, boolean isOnBlo searchPos.setWithOffset(lightPos, aoFace.neighbors[0]); searchState = level.getBlockState(searchPos); - final int light0 = dataProvider.light(searchPos, searchState); - final float ao0 = dataProvider.ao(searchPos, searchState); + final int light0 = lightCache.getLightCoords(searchState, level, searchPos); + final float ao0 = lightCache.getShadeBrightness(searchState, level, searchPos); if (!Indigo.FIX_SMOOTH_LIGHTING_OFFSET) { searchPos.move(lightFace); searchState = level.getBlockState(searchPos); } - final boolean isClear0 = !searchState.isViewBlocking(level, searchPos) || searchState.getLightBlock() == 0; + final boolean isClear0 = !searchState.isViewBlocking(level, searchPos) || searchState.getLightDampening() == 0; searchPos.setWithOffset(lightPos, aoFace.neighbors[1]); searchState = level.getBlockState(searchPos); - final int light1 = dataProvider.light(searchPos, searchState); - final float ao1 = dataProvider.ao(searchPos, searchState); + final int light1 = lightCache.getLightCoords(searchState, level, searchPos); + final float ao1 = lightCache.getShadeBrightness(searchState, level, searchPos); if (!Indigo.FIX_SMOOTH_LIGHTING_OFFSET) { searchPos.move(lightFace); searchState = level.getBlockState(searchPos); } - final boolean isClear1 = !searchState.isViewBlocking(level, searchPos) || searchState.getLightBlock() == 0; + final boolean isClear1 = !searchState.isViewBlocking(level, searchPos) || searchState.getLightDampening() == 0; searchPos.setWithOffset(lightPos, aoFace.neighbors[2]); searchState = level.getBlockState(searchPos); - final int light2 = dataProvider.light(searchPos, searchState); - final float ao2 = dataProvider.ao(searchPos, searchState); + final int light2 = lightCache.getLightCoords(searchState, level, searchPos); + final float ao2 = lightCache.getShadeBrightness(searchState, level, searchPos); if (!Indigo.FIX_SMOOTH_LIGHTING_OFFSET) { searchPos.move(lightFace); searchState = level.getBlockState(searchPos); } - final boolean isClear2 = !searchState.isViewBlocking(level, searchPos) || searchState.getLightBlock() == 0; + final boolean isClear2 = !searchState.isViewBlocking(level, searchPos) || searchState.getLightDampening() == 0; searchPos.setWithOffset(lightPos, aoFace.neighbors[3]); searchState = level.getBlockState(searchPos); - final int light3 = dataProvider.light(searchPos, searchState); - final float ao3 = dataProvider.ao(searchPos, searchState); + final int light3 = lightCache.getLightCoords(searchState, level, searchPos); + final float ao3 = lightCache.getShadeBrightness(searchState, level, searchPos); if (!Indigo.FIX_SMOOTH_LIGHTING_OFFSET) { searchPos.move(lightFace); searchState = level.getBlockState(searchPos); } - final boolean isClear3 = !searchState.isViewBlocking(level, searchPos) || searchState.getLightBlock() == 0; + final boolean isClear3 = !searchState.isViewBlocking(level, searchPos) || searchState.getLightDampening() == 0; // c = corner - values at corners of face int cLight0, cLight1, cLight2, cLight3; @@ -422,9 +439,9 @@ private void computeFace(AoFaceData result, Direction lightFace, boolean isOnBlo } else { searchPos.setWithOffset(lightPos, aoFace.neighbors[0]).move(aoFace.neighbors[2]); searchState = level.getBlockState(searchPos); - cAo0 = dataProvider.ao(searchPos, searchState); - cLight0 = dataProvider.light(searchPos, searchState); - cIsClear0 = !searchState.isViewBlocking(level, searchPos) || searchState.getLightBlock() == 0; + cAo0 = lightCache.getShadeBrightness(searchState, level, searchPos); + cLight0 = lightCache.getLightCoords(searchState, level, searchPos); + cIsClear0 = !searchState.isViewBlocking(level, searchPos) || searchState.getLightDampening() == 0; } if (!isClear3 && !isClear0) { @@ -434,9 +451,9 @@ private void computeFace(AoFaceData result, Direction lightFace, boolean isOnBlo } else { searchPos.setWithOffset(lightPos, aoFace.neighbors[0]).move(aoFace.neighbors[3]); searchState = level.getBlockState(searchPos); - cAo1 = dataProvider.ao(searchPos, searchState); - cLight1 = dataProvider.light(searchPos, searchState); - cIsClear1 = !searchState.isViewBlocking(level, searchPos) || searchState.getLightBlock() == 0; + cAo1 = lightCache.getShadeBrightness(searchState, level, searchPos); + cLight1 = lightCache.getLightCoords(searchState, level, searchPos); + cIsClear1 = !searchState.isViewBlocking(level, searchPos) || searchState.getLightDampening() == 0; } if (!isClear2 && !isClear1) { @@ -447,9 +464,9 @@ private void computeFace(AoFaceData result, Direction lightFace, boolean isOnBlo } else { searchPos.setWithOffset(lightPos, aoFace.neighbors[1]).move(aoFace.neighbors[2]); searchState = level.getBlockState(searchPos); - cAo2 = dataProvider.ao(searchPos, searchState); - cLight2 = dataProvider.light(searchPos, searchState); - cIsClear2 = !searchState.isViewBlocking(level, searchPos) || searchState.getLightBlock() == 0; + cAo2 = lightCache.getShadeBrightness(searchState, level, searchPos); + cLight2 = lightCache.getLightCoords(searchState, level, searchPos); + cIsClear2 = !searchState.isViewBlocking(level, searchPos) || searchState.getLightDampening() == 0; } if (!isClear3 && !isClear1) { @@ -460,9 +477,9 @@ private void computeFace(AoFaceData result, Direction lightFace, boolean isOnBlo } else { searchPos.setWithOffset(lightPos, aoFace.neighbors[1]).move(aoFace.neighbors[3]); searchState = level.getBlockState(searchPos); - cAo3 = dataProvider.ao(searchPos, searchState); - cLight3 = dataProvider.light(searchPos, searchState); - cIsClear3 = !searchState.isViewBlocking(level, searchPos) || searchState.getLightBlock() == 0; + cAo3 = lightCache.getShadeBrightness(searchState, level, searchPos); + cLight3 = lightCache.getLightCoords(searchState, level, searchPos); + cIsClear3 = !searchState.isViewBlocking(level, searchPos) || searchState.getLightDampening() == 0; } // If on block face and neighbor isn't occluding, "center" will be neighbor light @@ -478,15 +495,15 @@ private void computeFace(AoFaceData result, Direction lightFace, boolean isOnBlo // both are false, the vanilla logic caused inset faces against non-solid blocks to be lit discontinuously (i.e. // dark room with active sculk sensor above slabs). if (isOnBlockFace && !searchState.isSolidRender()) { - lightCenter = dataProvider.light(searchPos, searchState); - isClearCenter = !searchState.isViewBlocking(level, searchPos) || searchState.getLightBlock() == 0; + lightCenter = lightCache.getLightCoords(searchState, level, searchPos); + isClearCenter = !searchState.isViewBlocking(level, searchPos) || searchState.getLightDampening() == 0; } else { - lightCenter = dataProvider.light(pos, blockState); - isClearCenter = !blockState.isViewBlocking(level, pos) || blockState.getLightBlock() == 0; + lightCenter = lightCache.getLightCoords(blockState, level, pos); + isClearCenter = !blockState.isViewBlocking(level, pos) || blockState.getLightDampening() == 0; } - float aoCenter = dataProvider.ao(lightPos, level.getBlockState(lightPos)); - float shadeBrightness = level.getShade(lightFace, shade); + float aoCenter = lightCache.getShadeBrightness(level.getBlockState(lightPos), level, lightPos); + float shadeBrightness = shade ? level.cardinalLighting().byFace(lightFace) : level.cardinalLighting().up(); result.a0 = ((ao3 + ao0 + cAo1 + aoCenter) * 0.25F) * shadeBrightness; result.a1 = ((ao2 + ao0 + cAo0 + aoCenter) * 0.25F) * shadeBrightness; diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/aocalc/FlatLighter.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/aocalc/FlatLighter.java new file mode 100644 index 00000000000..c4e9f3df013 --- /dev/null +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/aocalc/FlatLighter.java @@ -0,0 +1,163 @@ +/* + * 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.aocalc; + +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 org.joml.Vector3fc; + +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.BlockModelLighter; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.ARGB; +import net.minecraft.world.level.CardinalLighting; +import net.minecraft.world.level.block.state.BlockState; + +import net.fabricmc.fabric.impl.client.indigo.Indigo; +import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl; +import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.QuadViewImpl; + +public class FlatLighter { + private final BlockPos.MutableBlockPos scratchPos = new BlockPos.MutableBlockPos(); + private final BlockModelLighter.Cache lightCache; + + public FlatLighter(BlockModelLighter.Cache lightCache) { + this.lightCache = lightCache; + } + + /** + * Starting in 1.16 flat shading uses dimension-specific diffuse factors that can be < 1.0 + * even for un-shaded quads. These are also applied with AO shading but that is done in AO calculator. + */ + public void applyDirectionalBrightness(CardinalLighting cardinalLighting, MutableQuadViewImpl quad, boolean vanillaShade) { + if (!quad.diffuseShade()) { + final float directionalBrightness = cardinalLighting.up(); + + if (directionalBrightness != 1.0f) { + for (int i = 0; i < 4; i++) { + quad.color(i, ARGB.scaleRGB(quad.color(i), directionalBrightness)); + } + } + } else if ((Indigo.AMBIENT_OCCLUSION_MODE == AoConfig.HYBRID && !vanillaShade) || Indigo.AMBIENT_OCCLUSION_MODE == AoConfig.ENHANCED) { + // ^ Check the AO mode to match how shade is applied during smooth lighting + if (quad.hasAllVertexNormals()) { + for (int i = 0; i < 4; i++) { + final float directionalBrightness = normalShade(cardinalLighting, quad.normalX(i), quad.normalY(i), quad.normalZ(i)); + quad.color(i, ARGB.scaleRGB(quad.color(i), directionalBrightness)); + } + } else { + final float directionalBrightness; + + if ((quad.geometryFlags() & AXIS_ALIGNED_FLAG) != 0) { + directionalBrightness = cardinalLighting.byFace(quad.lightFace()); + } else { + Vector3fc faceNormal = quad.faceNormal(); + directionalBrightness = normalShade(cardinalLighting, faceNormal.x(), faceNormal.y(), faceNormal.z()); + } + + if (quad.hasVertexNormals()) { + for (int i = 0; i < 4; i++) { + float shade; + + if (quad.hasNormal(i)) { + shade = normalShade(cardinalLighting, quad.normalX(i), quad.normalY(i), quad.normalZ(i)); + } else { + shade = directionalBrightness; + } + + quad.color(i, ARGB.scaleRGB(quad.color(i), shade)); + } + } else { + if (directionalBrightness != 1.0f) { + for (int i = 0; i < 4; i++) { + quad.color(i, ARGB.scaleRGB(quad.color(i), directionalBrightness)); + } + } + } + } + } else { + final float directionalBrightness = cardinalLighting.byFace(quad.lightFace()); + + if (directionalBrightness != 1.0f) { + for (int i = 0; i < 4; i++) { + quad.color(i, ARGB.scaleRGB(quad.color(i), directionalBrightness)); + } + } + } + } + + /** + * Finds mean of per-face shading factors weighted by normal components. + * Not how light actually works but the vanilla diffuse shading model is a hack to start with + * and this gives reasonable results for non-cubic surfaces in a vanilla-style renderer. + */ + private static float normalShade(CardinalLighting cardinalLighting, float normalX, float normalY, float normalZ) { + float sum = 0; + float div = 0; + + if (normalX > 0) { + sum += normalX * cardinalLighting.byFace(Direction.EAST); + div += normalX; + } else if (normalX < 0) { + sum += -normalX * cardinalLighting.byFace(Direction.WEST); + div -= normalX; + } + + if (normalY > 0) { + sum += normalY * cardinalLighting.byFace(Direction.UP); + div += normalY; + } else if (normalY < 0) { + sum += -normalY * cardinalLighting.byFace(Direction.DOWN); + div -= normalY; + } + + if (normalZ > 0) { + sum += normalZ * cardinalLighting.byFace(Direction.SOUTH); + div += normalZ; + } else if (normalZ < 0) { + sum += -normalZ * cardinalLighting.byFace(Direction.NORTH); + div -= normalZ; + } + + return sum / div; + } + + /** + * Handles geometry-based check for using self light or neighbor light. + * That logic only applies in flat lighting. + */ + public int light(BlockAndTintGetter level, BlockState state, BlockPos pos, QuadViewImpl quad) { + scratchPos.set(pos); + + // To mirror Vanilla's behavior, if the face has a cull-face, always sample the light value + // offset in that direction. See net.minecraft.client.renderer.block.ModelBlockRenderer.tesselateFlat + // for reference. + if (quad.cullFace() != null) { + scratchPos.move(quad.cullFace()); + } else { + final int flags = quad.geometryFlags(); + + if ((flags & LIGHT_FACE_FLAG) != 0 || ((flags & AXIS_ALIGNED_FLAG) != 0 && state.isCollisionShapeFullBlock(level, pos))) { + scratchPos.move(quad.lightFace()); + } + } + + return lightCache.getLightCoords(state, level, scratchPos); + } +} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/helper/ColorHelper.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/helper/ColorHelper.java deleted file mode 100644 index 42fe3f53152..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/helper/ColorHelper.java +++ /dev/null @@ -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.helper; - -/** - * Static routines of general utility for renderer implementations. - * Renderers are not required to use these helpers, but they were - * designed to be usable without the default renderer. - */ -public final class ColorHelper { - private ColorHelper() { } - - /** - * Component-wise max. - */ - public static int maxLight(int l0, int l1) { - if (l0 == 0) return l1; - if (l1 == 0) return l0; - - return Math.max(l0 & 0xFFFF, l1 & 0xFFFF) | Math.max(l0 & 0xFFFF0000, l1 & 0xFFFF0000); - } -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/helper/GeometryHelper.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/helper/GeometryHelper.java index 66e725b4afd..1f7d3d1fd7b 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/helper/GeometryHelper.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/helper/GeometryHelper.java @@ -21,7 +21,7 @@ import org.joml.Vector3fc; import net.minecraft.client.renderer.FaceInfo; -import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.resources.model.geometry.BakedQuad; import net.minecraft.core.Direction; import net.minecraft.core.Direction.Axis; import net.minecraft.core.Direction.AxisDirection; diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/EncodingFormat.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/EncodingFormat.java index 617ff136300..4db5b96c92e 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/EncodingFormat.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/EncodingFormat.java @@ -17,13 +17,12 @@ package net.fabricmc.fabric.impl.client.indigo.renderer.mesh; import com.google.common.base.Preconditions; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.VertexFormat; import org.apache.commons.lang3.ArrayUtils; import org.jspecify.annotations.Nullable; import net.minecraft.client.renderer.chunk.ChunkSectionLayer; import net.minecraft.client.renderer.item.ItemStackRenderState; +import net.minecraft.client.renderer.rendertype.RenderType; import net.minecraft.core.Direction; import net.minecraft.util.Mth; @@ -55,23 +54,36 @@ private EncodingFormat() { } static final int VERTEX_V; static final int VERTEX_LIGHTMAP; static final int VERTEX_NORMAL; - public static final int VERTEX_STRIDE; + private static final int VERTEX_POSITION_BYTES = Float.BYTES; + private static final int VERTEX_COLOR_BYTES = Integer.BYTES; + private static final int VERTEX_UV_BYTES = Float.BYTES; + private static final int VERTEX_LIGHTMAP_BYTES = Integer.BYTES; + private static final int VERTEX_NORMAL_BYTES = Integer.BYTES; + private static final int VERTEX_COLOR_SIZE = VERTEX_COLOR_BYTES / 4; + private static final int VERTEX_UV_SIZE = VERTEX_UV_BYTES / 4; + private static final int VERTEX_LIGHTMAP_SIZE = VERTEX_LIGHTMAP_BYTES / 4; + private static final int VERTEX_NORMAL_SIZE = VERTEX_NORMAL_BYTES / 4; + private static final int VERTEX_POSITION_SIZE = VERTEX_POSITION_BYTES / 4; + public static final int VERTEX_STRIDE = + 3 * VERTEX_POSITION_SIZE + + VERTEX_COLOR_SIZE + + 2 * VERTEX_UV_SIZE + + VERTEX_LIGHTMAP_SIZE + + VERTEX_NORMAL_SIZE; public static final int QUAD_STRIDE; public static final int QUAD_STRIDE_BYTES; public static final int TOTAL_STRIDE; static { - final VertexFormat format = DefaultVertexFormat.BLOCK; VERTEX_X = HEADER_STRIDE + 0; - VERTEX_Y = HEADER_STRIDE + 1; - VERTEX_Z = HEADER_STRIDE + 2; - VERTEX_COLOR = HEADER_STRIDE + 3; - VERTEX_U = HEADER_STRIDE + 4; - VERTEX_V = VERTEX_U + 1; - VERTEX_LIGHTMAP = HEADER_STRIDE + 6; - VERTEX_NORMAL = HEADER_STRIDE + 7; - VERTEX_STRIDE = format.getVertexSize() / 4; + VERTEX_Y = VERTEX_X + VERTEX_POSITION_SIZE; + VERTEX_Z = VERTEX_Y + VERTEX_POSITION_SIZE; + VERTEX_COLOR = VERTEX_Z + VERTEX_COLOR_SIZE; + VERTEX_U = VERTEX_COLOR + VERTEX_UV_SIZE; + VERTEX_V = VERTEX_U + VERTEX_UV_SIZE; + VERTEX_LIGHTMAP = VERTEX_V + VERTEX_LIGHTMAP_SIZE; + VERTEX_NORMAL = VERTEX_LIGHTMAP + VERTEX_NORMAL_SIZE; QUAD_STRIDE = VERTEX_STRIDE * 4; QUAD_STRIDE_BYTES = QUAD_STRIDE * 4; TOTAL_STRIDE = HEADER_STRIDE + QUAD_STRIDE; @@ -80,8 +92,10 @@ private EncodingFormat() { } private static final int DIRECTION_COUNT = Direction.values().length; private static final int NULLABLE_DIRECTION_COUNT = DIRECTION_COUNT + 1; - private static final @Nullable ChunkSectionLayer[] NULLABLE_CHUNK_SECTION_LAYERS = ArrayUtils.add(ChunkSectionLayer.values(), null); - private static final int NULLABLE_CHUNK_SECTION_LAYER_COUNT = NULLABLE_CHUNK_SECTION_LAYERS.length; + private static final ChunkSectionLayer[] CHUNK_SECTION_LAYERS = ChunkSectionLayer.values(); + private static final int CHUNK_SECTION_LAYER_COUNT = CHUNK_SECTION_LAYERS.length; + private static final RenderType[] ITEM_RENDER_TYPES = ItemRenderType.RENDER_TYPES; + private static final int ITEM_RENDER_TYPE_COUNT = ITEM_RENDER_TYPES.length; private static final TriState[] TRI_STATES = TriState.values(); private static final int TRI_STATE_COUNT = TRI_STATES.length; private static final ItemStackRenderState.@Nullable FoilType[] NULLABLE_FOIL_TYPES = ArrayUtils.add(ItemStackRenderState.FoilType.values(), null); @@ -91,44 +105,48 @@ private EncodingFormat() { } private static final QuadAtlas[] QUAD_ATLASES = QuadAtlas.values(); private static final int QUAD_ATLAS_COUNT = QUAD_ATLASES.length; - private static final int NULL_CHUNK_LAYER_INDEX = NULLABLE_CHUNK_SECTION_LAYER_COUNT - 1; private static final int NULL_FOIL_TYPE_INDEX = NULLABLE_FOIL_TYPE_COUNT - 1; private static final int CULL_BIT_LENGTH = Mth.ceillog2(NULLABLE_DIRECTION_COUNT); private static final int LIGHT_BIT_LENGTH = Mth.ceillog2(DIRECTION_COUNT); private static final int NORMALS_BIT_LENGTH = 4; private static final int GEOMETRY_BIT_LENGTH = GeometryHelper.FLAG_BIT_COUNT; - private static final int CHUNK_LAYER_BIT_LENGTH = Mth.ceillog2( - NULLABLE_CHUNK_SECTION_LAYER_COUNT); + private static final int QUAD_ATLAS_BIT_LENGTH = Mth.ceillog2(QUAD_ATLAS_COUNT); + private static final int CHUNK_LAYER_BIT_LENGTH = Mth.ceillog2(CHUNK_SECTION_LAYER_COUNT); + private static final int ITEM_RENDER_TYPE_BIT_LENGTH = Mth.ceillog2(ITEM_RENDER_TYPE_COUNT); private static final int EMISSIVE_BIT_LENGTH = 1; private static final int DIFFUSE_BIT_LENGTH = 1; private static final int AO_BIT_LENGTH = Mth.ceillog2(TRI_STATE_COUNT); private static final int FOIL_TYPE_BIT_LENGTH = Mth.ceillog2( NULLABLE_FOIL_TYPE_COUNT); private static final int SHADE_MODE_BIT_LENGTH = Mth.ceillog2(SHADE_MODE_COUNT); - private static final int QUAD_ATLAS_BIT_LENGTH = Mth.ceillog2(QUAD_ATLAS_COUNT); + private static final int ANIMATED_BIT_LENGTH = 1; private static final int CULL_BIT_OFFSET = 0; private static final int LIGHT_BIT_OFFSET = CULL_BIT_OFFSET + CULL_BIT_LENGTH; private static final int NORMALS_BIT_OFFSET = LIGHT_BIT_OFFSET + LIGHT_BIT_LENGTH; private static final int GEOMETRY_BIT_OFFSET = NORMALS_BIT_OFFSET + NORMALS_BIT_LENGTH; - private static final int CHUNK_LAYER_BIT_OFFSET = GEOMETRY_BIT_OFFSET + GEOMETRY_BIT_LENGTH; - private static final int EMISSIVE_BIT_OFFSET = CHUNK_LAYER_BIT_OFFSET + CHUNK_LAYER_BIT_LENGTH; + private static final int QUAD_ATLAS_BIT_OFFSET = GEOMETRY_BIT_OFFSET + GEOMETRY_BIT_LENGTH; + private static final int CHUNK_LAYER_BIT_OFFSET = QUAD_ATLAS_BIT_OFFSET + QUAD_ATLAS_BIT_LENGTH; + private static final int ITEM_RENDER_TYPE_BIT_OFFSET = CHUNK_LAYER_BIT_OFFSET + CHUNK_LAYER_BIT_LENGTH; + private static final int EMISSIVE_BIT_OFFSET = ITEM_RENDER_TYPE_BIT_OFFSET + ITEM_RENDER_TYPE_BIT_LENGTH; private static final int DIFFUSE_BIT_OFFSET = EMISSIVE_BIT_OFFSET + EMISSIVE_BIT_LENGTH; private static final int AO_BIT_OFFSET = DIFFUSE_BIT_OFFSET + DIFFUSE_BIT_LENGTH; private static final int FOIL_TYPE_BIT_OFFSET = AO_BIT_OFFSET + AO_BIT_LENGTH; private static final int SHADE_MODE_BIT_OFFSET = FOIL_TYPE_BIT_OFFSET + FOIL_TYPE_BIT_LENGTH; - private static final int QUAD_ATLAS_BIT_OFFSET = SHADE_MODE_BIT_OFFSET + SHADE_MODE_BIT_LENGTH; - private static final int TOTAL_BIT_LENGTH = QUAD_ATLAS_BIT_OFFSET + QUAD_ATLAS_BIT_LENGTH; + private static final int ANIMATED_BIT_OFFSET = SHADE_MODE_BIT_OFFSET + SHADE_MODE_BIT_LENGTH; + private static final int TOTAL_BIT_LENGTH = ANIMATED_BIT_OFFSET + ANIMATED_BIT_LENGTH; private static final int CULL_MASK = bitMask(CULL_BIT_LENGTH, CULL_BIT_OFFSET); private static final int LIGHT_MASK = bitMask(LIGHT_BIT_LENGTH, LIGHT_BIT_OFFSET); private static final int NORMALS_MASK = bitMask(NORMALS_BIT_LENGTH, NORMALS_BIT_OFFSET); private static final int GEOMETRY_MASK = bitMask(GEOMETRY_BIT_LENGTH, GEOMETRY_BIT_OFFSET); + private static final int QUAD_ATLAS_MASK = bitMask(QUAD_ATLAS_BIT_LENGTH, QUAD_ATLAS_BIT_OFFSET); private static final int CHUNK_LAYER_MASK = bitMask( CHUNK_LAYER_BIT_LENGTH, CHUNK_LAYER_BIT_OFFSET ); + private static final int ITEM_RENDER_TYPE_MASK = bitMask(ITEM_RENDER_TYPE_BIT_LENGTH, ITEM_RENDER_TYPE_BIT_OFFSET); private static final int EMISSIVE_MASK = bitMask(EMISSIVE_BIT_LENGTH, EMISSIVE_BIT_OFFSET); private static final int DIFFUSE_MASK = bitMask(DIFFUSE_BIT_LENGTH, DIFFUSE_BIT_OFFSET); private static final int AO_MASK = bitMask(AO_BIT_LENGTH, AO_BIT_OFFSET); @@ -136,7 +154,7 @@ private EncodingFormat() { } FOIL_TYPE_BIT_OFFSET ); private static final int SHADE_MODE_MASK = bitMask(SHADE_MODE_BIT_LENGTH, SHADE_MODE_BIT_OFFSET); - private static final int QUAD_ATLAS_MASK = bitMask(QUAD_ATLAS_BIT_LENGTH, QUAD_ATLAS_BIT_OFFSET); + private static final int ANIMATED_MASK = bitMask(ANIMATED_BIT_LENGTH, ANIMATED_BIT_OFFSET); static { Preconditions.checkArgument(TOTAL_BIT_LENGTH <= 32, "Indigo header encoding bit count (%s) exceeds integer bit length)", TOTAL_STRIDE); @@ -180,14 +198,28 @@ static int geometryFlags(int bits, int geometryFlags) { return (bits & ~GEOMETRY_MASK) | ((geometryFlags << GEOMETRY_BIT_OFFSET) & GEOMETRY_MASK); } - @Nullable + static QuadAtlas quadAtlas(int bits) { + return QUAD_ATLASES[(bits & QUAD_ATLAS_MASK) >>> QUAD_ATLAS_BIT_OFFSET]; + } + + static int quadAtlas(int bits, QuadAtlas quadAtlas) { + return (bits & ~QUAD_ATLAS_MASK) | (quadAtlas.ordinal() << QUAD_ATLAS_BIT_OFFSET); + } + static ChunkSectionLayer chunkLayer(int bits) { - return NULLABLE_CHUNK_SECTION_LAYERS[(bits & CHUNK_LAYER_MASK) >>> CHUNK_LAYER_BIT_OFFSET]; + return CHUNK_SECTION_LAYERS[(bits & CHUNK_LAYER_MASK) >>> CHUNK_LAYER_BIT_OFFSET]; + } + + static int chunkLayer(int bits, ChunkSectionLayer layer) { + return (bits & ~CHUNK_LAYER_MASK) | (layer.ordinal() << CHUNK_LAYER_BIT_OFFSET); + } + + static RenderType itemRenderType(int bits) { + return ITEM_RENDER_TYPES[(bits & ITEM_RENDER_TYPE_MASK) >>> ITEM_RENDER_TYPE_BIT_OFFSET]; } - static int chunkLayer(int bits, @Nullable ChunkSectionLayer layer) { - int index = layer == null ? NULL_CHUNK_LAYER_INDEX : layer.ordinal(); - return (bits & ~CHUNK_LAYER_MASK) | (index << CHUNK_LAYER_BIT_OFFSET); + static int itemRenderType(int bits, ItemRenderType renderType) { + return (bits & ~ITEM_RENDER_TYPE_MASK) | (renderType.ordinal() << ITEM_RENDER_TYPE_BIT_OFFSET); } static boolean emissive(int bits) { @@ -231,11 +263,11 @@ static int shadeMode(int bits, ShadeMode mode) { return (bits & ~SHADE_MODE_MASK) | (mode.ordinal() << SHADE_MODE_BIT_OFFSET); } - static QuadAtlas quadAtlas(int bits) { - return QUAD_ATLASES[(bits & QUAD_ATLAS_MASK) >>> QUAD_ATLAS_BIT_OFFSET]; + static boolean animated(int bits) { + return (bits & ANIMATED_MASK) != 0; } - static int quadAtlas(int bits, QuadAtlas quadAtlas) { - return (bits & ~QUAD_ATLAS_MASK) | (quadAtlas.ordinal() << QUAD_ATLAS_BIT_OFFSET); + static int animated(int bits, boolean animated) { + return animated ? (bits | ANIMATED_MASK) : (bits & ~ANIMATED_MASK); } } diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/ItemRenderType.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/ItemRenderType.java new file mode 100644 index 00000000000..d7cfb56c890 --- /dev/null +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/ItemRenderType.java @@ -0,0 +1,56 @@ +/* + * 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.mesh; + +import java.util.Arrays; +import java.util.Map; + +import net.minecraft.client.renderer.Sheets; +import net.minecraft.client.renderer.rendertype.RenderType; + +import net.fabricmc.fabric.api.client.renderer.v1.mesh.MutableQuadView; + +/** + * Allowed values for {@link MutableQuadView#itemRenderType(RenderType)}. + */ +enum ItemRenderType { + CUTOUT(Sheets.cutoutItemSheet()), + TRANSLUCENT(Sheets.translucentItemSheet()), + CUTOUT_BLOCK(Sheets.cutoutBlockItemSheet()), + TRANSLUCENT_BLOCK(Sheets.translucentBlockItemSheet()); + + static final RenderType[] RENDER_TYPES = Arrays.stream(ItemRenderType.values()).map(t -> t.renderType).toArray(RenderType[]::new); + static final Map RENDER_TYPE_2_ENUM; + + static { + RENDER_TYPE_2_ENUM = Map.of( + CUTOUT.renderType, CUTOUT, + TRANSLUCENT.renderType, TRANSLUCENT, + CUTOUT_BLOCK.renderType, CUTOUT_BLOCK, + TRANSLUCENT_BLOCK.renderType, TRANSLUCENT_BLOCK + ); + } + + // The atlas of the default render type should match the default QuadAtlas, which is currently BLOCK. + static final ItemRenderType DEFAULT = ItemRenderType.CUTOUT_BLOCK; + + final RenderType renderType; + + ItemRenderType(RenderType renderType) { + this.renderType = renderType; + } +} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/MutableQuadViewImpl.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/MutableQuadViewImpl.java index 4d6ab45c782..2fd04213037 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/MutableQuadViewImpl.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/MutableQuadViewImpl.java @@ -32,11 +32,11 @@ import org.jspecify.annotations.Nullable; import net.minecraft.client.model.geom.builders.UVPair; -import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.chunk.ChunkSectionLayer; 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.core.Direction; -import net.minecraft.util.LightCoordsUtil; import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadAtlas; import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter; @@ -57,7 +57,7 @@ * numbers. It also allows for a consistent interface for those transformations. */ public abstract class MutableQuadViewImpl extends QuadViewImpl implements QuadEmitter { - private static final QuadTransform NO_TRANSFORM = q -> true; + private static final QuadTransform NO_TRANSFORM = _ -> true; private static final int[] DEFAULT_QUAD_DATA = new int[EncodingFormat.TOTAL_STRIDE]; @@ -74,11 +74,13 @@ protected void emitDirectly() { // Apply non-zero defaults quad.color(-1, -1, -1, -1); quad.cullFace(null); - quad.chunkLayer(null); + quad.chunkLayer(ChunkSectionLayer.CUTOUT); + quad.itemRenderType(ItemRenderType.DEFAULT.renderType); quad.diffuseShade(true); quad.ambientOcclusion(TriState.DEFAULT); quad.foilType(null); quad.tintIndex(-1); + quad.animated(false); } private QuadTransform activeTransform = NO_TRANSFORM; @@ -95,12 +97,6 @@ protected void emitDirectly() { return true; }; - public final void clear() { - System.arraycopy(DEFAULT_QUAD_DATA, 0, data, baseIndex, EncodingFormat.TOTAL_STRIDE); - isGeometryInvalid = true; - nominalFace = null; - } - @Override public final MutableQuadViewImpl pos(int vertexIndex, float x, float y, float z) { final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X; @@ -111,6 +107,22 @@ public final MutableQuadViewImpl pos(int vertexIndex, float x, float y, float z) return this; } + // Much more efficient than default impl as it does not invalidate geometry + // FIXME FRAPI 26.1: some geometry flags should be invalidated, but partial invalidation might + // add too much complexity. in all existing code, geometry is never queried after calling this + // method, so the default implementation may be sufficient. + @Override + public final MutableQuadViewImpl translate(float x, float y, float z) { + for (int i = 0; i < 4; i++) { + final int index = baseIndex + i * VERTEX_STRIDE + VERTEX_X; + data[index] = Float.floatToRawIntBits(Float.intBitsToFloat(data[index]) + x); + data[index + 1] = Float.floatToRawIntBits(Float.intBitsToFloat(data[index + 1]) + y); + data[index + 2] = Float.floatToRawIntBits(Float.intBitsToFloat(data[index + 2]) + z); + } + + return this; + } + @Override public final MutableQuadViewImpl color(int vertexIndex, int color) { data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_COLOR] = color; @@ -175,10 +187,19 @@ public final MutableQuadViewImpl cullFace(@Nullable Direction face) { } @Override - public MutableQuadViewImpl chunkLayer(@Nullable ChunkSectionLayer layer) { - data[baseIndex + HEADER_BITS] = EncodingFormat.chunkLayer(data[baseIndex + HEADER_BITS], - layer - ); + public MutableQuadViewImpl chunkLayer(ChunkSectionLayer layer) { + data[baseIndex + HEADER_BITS] = EncodingFormat.chunkLayer(data[baseIndex + HEADER_BITS], layer); + return this; + } + + @Override + public MutableQuadViewImpl itemRenderType(RenderType renderType) { + ItemRenderType enumValue = ItemRenderType.RENDER_TYPE_2_ENUM.get(renderType); + + if (enumValue != null) { + data[baseIndex + HEADER_BITS] = EncodingFormat.itemRenderType(data[baseIndex + HEADER_BITS], enumValue); + } + return this; } @@ -216,6 +237,12 @@ public MutableQuadViewImpl shadeMode(ShadeMode mode) { return this; } + @Override + public MutableQuadViewImpl animated(boolean animated) { + data[baseIndex + HEADER_BITS] = EncodingFormat.animated(data[baseIndex + HEADER_BITS], animated); + return this; + } + @Override public MutableQuadViewImpl atlas(QuadAtlas quadAtlas) { data[baseIndex + HEADER_BITS] = EncodingFormat.quadAtlas(data[baseIndex + HEADER_BITS], quadAtlas); @@ -266,23 +293,18 @@ public final MutableQuadViewImpl fromBakedQuad(BakedQuad quad) { uv(2, UVPair.unpackU(packedUV2), UVPair.unpackV(packedUV2)); uv(3, UVPair.unpackU(packedUV3), UVPair.unpackV(packedUV3)); - int lightEmission = quad.lightEmission(); - int lightmap = LightCoordsUtil.pack(lightEmission, lightEmission); - lightmap(lightmap, lightmap, lightmap, lightmap); - normalFlags(0); nominalFace(quad.direction()); - emissive(lightEmission == 15); - diffuseShade(quad.shade()); - QuadAtlas atlas = QuadAtlas.of(quad.sprite().atlasLocation()); - - if (atlas == null) { - atlas = QuadAtlas.BLOCK; - } + materialInfo(quad.materialInfo()); + return this; + } - atlas(atlas); - tintIndex(quad.tintIndex()); + @Override + public final MutableQuadViewImpl clear() { + System.arraycopy(DEFAULT_QUAD_DATA, 0, data, baseIndex, EncodingFormat.TOTAL_STRIDE); + isGeometryInvalid = true; + nominalFace = null; return this; } diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/QuadViewImpl.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/QuadViewImpl.java index 8f45f817b05..5bd1b6f596f 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/QuadViewImpl.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/mesh/QuadViewImpl.java @@ -30,13 +30,18 @@ import static net.fabricmc.fabric.impl.client.indigo.renderer.mesh.EncodingFormat.VERTEX_Y; import static net.fabricmc.fabric.impl.client.indigo.renderer.mesh.EncodingFormat.VERTEX_Z; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import org.joml.Matrix4f; import org.joml.Vector2f; import org.joml.Vector3f; import org.joml.Vector3fc; +import org.joml.Vector4f; import org.jspecify.annotations.Nullable; import net.minecraft.client.renderer.chunk.ChunkSectionLayer; import net.minecraft.client.renderer.item.ItemStackRenderState; +import net.minecraft.client.renderer.rendertype.RenderType; import net.minecraft.core.Direction; import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadAtlas; @@ -63,6 +68,11 @@ public class QuadViewImpl implements QuadView { /** Beginning of the quad. Also the header index. */ protected int baseIndex = 0; + // Temporary vectors used when buffering to a VertexConsumer + private final Vector4f posVec = new Vector4f(); + private final Vector3f normalVec = new Vector3f(); + private final Vector3f normalVec1 = new Vector3f(); + /** * Decodes necessary state from the backing data array. * The encoded data must contain valid computed geometry. @@ -240,11 +250,20 @@ public final Direction cullFace() { } @Override - @Nullable + public QuadAtlas atlas() { + return EncodingFormat.quadAtlas(data[baseIndex + HEADER_BITS]); + } + + @Override public ChunkSectionLayer chunkLayer() { return EncodingFormat.chunkLayer(data[baseIndex + HEADER_BITS]); } + @Override + public RenderType itemRenderType() { + return EncodingFormat.itemRenderType(data[baseIndex + HEADER_BITS]); + } + @Override public boolean emissive() { return EncodingFormat.emissive(data[baseIndex + HEADER_BITS]); @@ -271,8 +290,8 @@ public ShadeMode shadeMode() { } @Override - public QuadAtlas atlas() { - return EncodingFormat.quadAtlas(data[baseIndex + HEADER_BITS]); + public boolean animated() { + return EncodingFormat.animated(data[baseIndex + HEADER_BITS]); } @Override @@ -284,4 +303,76 @@ public final int tintIndex() { public final int tag() { return data[baseIndex + HEADER_TAG]; } + + @Override + public final void buffer(int overlayCoords, VertexConsumer vertexConsumer) { + if (!hasVertexNormals()) { + final Vector3fc faceNormal = faceNormal(); + + for (int i = 0; i < 4; i++) { + vertexConsumer.addVertex(x(i), y(i), z(i), color(i), u(i), v(i), overlayCoords, lightmap(i), faceNormal.x(), faceNormal.y(), faceNormal.z()); + } + } else if (hasAllVertexNormals()) { + final Vector3f normalVec = this.normalVec; + + for (int i = 0; i < 4; i++) { + copyNormal(i, normalVec); + vertexConsumer.addVertex(x(i), y(i), z(i), color(i), u(i), v(i), overlayCoords, lightmap(i), normalVec.x(), normalVec.y(), normalVec.z()); + } + } else { + final Vector3f normalVec = this.normalVec; + final Vector3fc faceNormal = faceNormal(); + + for (int i = 0; i < 4; i++) { + if (hasNormal(i)) { + copyNormal(i, normalVec); + } else { + normalVec.set(faceNormal); + } + + vertexConsumer.addVertex(x(i), y(i), z(i), color(i), u(i), v(i), overlayCoords, lightmap(i), normalVec.x(), normalVec.y(), normalVec.z()); + } + } + } + + @Override + public final void buffer(int overlayCoords, PoseStack.Pose pose, VertexConsumer vertexConsumer) { + final Vector4f posVec = this.posVec; + final Vector3f normalVec = this.normalVec; + final Matrix4f posMatrix = pose.pose(); + + if (!hasVertexNormals()) { + pose.transformNormal(faceNormal(), normalVec); + + for (int i = 0; i < 4; i++) { + posVec.set(x(i), y(i), z(i), 1.0f); + posVec.mul(posMatrix); + vertexConsumer.addVertex(posVec.x(), posVec.y(), posVec.z(), color(i), u(i), v(i), overlayCoords, lightmap(i), normalVec.x(), normalVec.y(), normalVec.z()); + } + } else if (hasAllVertexNormals()) { + for (int i = 0; i < 4; i++) { + posVec.set(x(i), y(i), z(i), 1.0f); + posVec.mul(posMatrix); + copyNormal(i, normalVec); + pose.transformNormal(normalVec, normalVec); + vertexConsumer.addVertex(posVec.x(), posVec.y(), posVec.z(), color(i), u(i), v(i), overlayCoords, lightmap(i), normalVec.x(), normalVec.y(), normalVec.z()); + } + } else { + final Vector3f transformedFaceNormal = pose.transformNormal(faceNormal(), normalVec1); + + for (int i = 0; i < 4; i++) { + posVec.set(x(i), y(i), z(i), 1.0f); + posVec.mul(posMatrix); + + if (hasNormal(i)) { + copyNormal(i, normalVec); + pose.transformNormal(normalVec, normalVec); + } else { + normalVec.set(transformedFaceNormal); + } + + vertexConsumer.addVertex(posVec.x(), posVec.y(), posVec.z(), color(i), u(i), v(i), overlayCoords, lightmap(i), normalVec.x(), normalVec.y(), normalVec.z()); + } + } + } } diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/AbstractRenderContext.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/AbstractRenderContext.java deleted file mode 100644 index 51f910cc8fc..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/AbstractRenderContext.java +++ /dev/null @@ -1,81 +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 com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import org.joml.Matrix4f; -import org.joml.Vector3f; -import org.joml.Vector4f; - -import net.fabricmc.fabric.api.client.renderer.v1.mesh.QuadEmitter; -import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.EncodingFormat; -import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl; - -public abstract class AbstractRenderContext { - private final MutableQuadViewImpl editorQuad = new MutableQuadViewImpl() { - { - data = new int[EncodingFormat.TOTAL_STRIDE]; - clear(); - } - - @Override - protected void emitDirectly() { - bufferQuad(this); - } - }; - - private final Vector4f posVec = new Vector4f(); - private final Vector3f normalVec = new Vector3f(); - - protected PoseStack.Pose pose; - protected int overlay; - - protected QuadEmitter getEmitter() { - editorQuad.clear(); - return editorQuad; - } - - protected abstract void bufferQuad(MutableQuadViewImpl quad); - - /** final output step, common to all renders. */ - protected void bufferQuad(MutableQuadViewImpl quad, VertexConsumer vertexConsumer) { - final Vector4f posVec = this.posVec; - final Vector3f normalVec = this.normalVec; - final PoseStack.Pose pose = this.pose; - final Matrix4f posMatrix = pose.pose(); - final boolean useNormals = quad.hasVertexNormals(); - - if (useNormals) { - quad.populateMissingNormals(); - } else { - pose.transformNormal(quad.faceNormal(), normalVec); - } - - for (int i = 0; i < 4; i++) { - posVec.set(quad.x(i), quad.y(i), quad.z(i), 1.0f); - posVec.mul(posMatrix); - - if (useNormals) { - quad.copyNormal(i, normalVec); - pose.transformNormal(normalVec, normalVec); - } - - vertexConsumer.addVertex(posVec.x(), posVec.y(), posVec.z(), quad.color(i), quad.u(i), quad.v(i), overlay, quad.lightmap(i), normalVec.x(), normalVec.y(), normalVec.z()); - } - } -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/AbstractTerrainRenderContext.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/AbstractTerrainRenderContext.java deleted file mode 100644 index d56979849a2..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/AbstractTerrainRenderContext.java +++ /dev/null @@ -1,254 +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 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 com.mojang.blaze3d.vertex.VertexConsumer; -import org.joml.Vector3fc; -import org.jspecify.annotations.Nullable; - -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.ARGB; -import net.minecraft.util.LightCoordsUtil; -import net.minecraft.world.level.block.state.BlockState; - -import net.fabricmc.fabric.api.client.renderer.v1.mesh.ShadeMode; -import net.fabricmc.fabric.impl.client.indigo.Indigo; -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.MutableQuadViewImpl; - -public abstract class AbstractTerrainRenderContext extends AbstractRenderContext { - protected final BlockRenderInfo blockInfo = new BlockRenderInfo(); - protected final LightDataProvider lightDataProvider; - private final AoCalculator aoCalc; - - private int cachedTintIndex = -1; - private int cachedTint; - - private final BlockPos.MutableBlockPos lightPos = new BlockPos.MutableBlockPos(); - - protected AbstractTerrainRenderContext() { - lightDataProvider = createLightDataProvider(blockInfo); - aoCalc = new AoCalculator(blockInfo, lightDataProvider); - } - - protected abstract LightDataProvider createLightDataProvider(BlockRenderInfo blockInfo); - - @Nullable - protected abstract VertexConsumer getVertexConsumer(ChunkSectionLayer layer); - - /** Must be called before buffering a block model. */ - protected void prepare(BlockPos pos, BlockState state) { - blockInfo.prepareForBlock(pos, state); - aoCalc.clear(); - cachedTintIndex = -1; - } - - @Override - protected void bufferQuad(MutableQuadViewImpl quad) { - if (blockInfo.shouldCullSide(quad.cullFace())) { - return; - } - - final VertexConsumer vertexConsumer = getVertexConsumer(blockInfo.effectiveChunkLayer(quad.chunkLayer())); - - if (vertexConsumer == null) { - return; - } - - final boolean ao = blockInfo.effectiveAo(quad.ambientOcclusion()); - final boolean vanillaShade = quad.shadeMode() == ShadeMode.VANILLA; - - tintQuad(quad); - shadeQuad(quad, ao, quad.emissive(), vanillaShade); - bufferQuad(quad, vertexConsumer); - } - - private void tintQuad(MutableQuadViewImpl quad) { - int tintIndex = quad.tintIndex(); - - if (tintIndex != -1) { - final int tint; - - if (tintIndex == cachedTintIndex) { - tint = cachedTint; - } else { - cachedTint = tint = blockInfo.blockColor(tintIndex); - cachedTintIndex = tintIndex; - } - - for (int i = 0; i < 4; i++) { - quad.color(i, ARGB.multiply(quad.color(i), tint)); - } - } - } - - private void shadeQuad(MutableQuadViewImpl quad, boolean ao, boolean emissive, boolean vanillaShade) { - // routines below have a bit of copy-paste code reuse to avoid conditional execution inside a hot loop - if (ao) { - aoCalc.compute(quad, vanillaShade); - - if (emissive) { - for (int i = 0; i < 4; i++) { - quad.color(i, ARGB.scaleRGB(quad.color(i), aoCalc.ao[i])); - quad.lightmap(i, LightCoordsUtil.FULL_BRIGHT); - } - } else { - for (int i = 0; i < 4; i++) { - quad.color(i, ARGB.scaleRGB(quad.color(i), aoCalc.ao[i])); - quad.lightmap(i, ColorHelper.maxLight(quad.lightmap(i), aoCalc.light[i])); - } - } - } else { - shadeFlatQuad(quad, vanillaShade); - - if (emissive) { - for (int i = 0; i < 4; i++) { - quad.lightmap(i, LightCoordsUtil.FULL_BRIGHT); - } - } else { - final int light = flatLight(quad); - - for (int i = 0; i < 4; i++) { - quad.lightmap(i, ColorHelper.maxLight(quad.lightmap(i), light)); - } - } - } - } - - /** - * Starting in 1.16 flat shading uses dimension-specific diffuse factors that can be < 1.0 - * even for un-shaded quads. These are also applied with AO shading but that is done in AO calculator. - */ - private void shadeFlatQuad(MutableQuadViewImpl quad, boolean vanillaShade) { - final boolean hasShade = quad.diffuseShade(); - - // Check the AO mode to match how shade is applied during smooth lighting - if ((Indigo.AMBIENT_OCCLUSION_MODE == AoConfig.HYBRID && !vanillaShade) || Indigo.AMBIENT_OCCLUSION_MODE == AoConfig.ENHANCED) { - if (quad.hasAllVertexNormals()) { - for (int i = 0; i < 4; i++) { - float shade = normalShade(quad.normalX(i), quad.normalY(i), quad.normalZ(i), hasShade); - quad.color(i, ARGB.scaleRGB(quad.color(i), shade)); - } - } else { - final float faceShade; - - if ((quad.geometryFlags() & AXIS_ALIGNED_FLAG) != 0) { - faceShade = blockInfo.level.getShade(quad.lightFace(), hasShade); - } else { - Vector3fc faceNormal = quad.faceNormal(); - faceShade = normalShade(faceNormal.x(), faceNormal.y(), faceNormal.z(), hasShade); - } - - if (quad.hasVertexNormals()) { - for (int i = 0; i < 4; i++) { - float shade; - - if (quad.hasNormal(i)) { - shade = normalShade(quad.normalX(i), quad.normalY(i), quad.normalZ(i), hasShade); - } else { - shade = faceShade; - } - - quad.color(i, ARGB.scaleRGB(quad.color(i), shade)); - } - } else { - if (faceShade != 1.0f) { - for (int i = 0; i < 4; i++) { - quad.color(i, ARGB.scaleRGB(quad.color(i), faceShade)); - } - } - } - } - } else { - final float faceShade = blockInfo.level.getShade(quad.lightFace(), hasShade); - - if (faceShade != 1.0f) { - for (int i = 0; i < 4; i++) { - quad.color(i, ARGB.scaleRGB(quad.color(i), faceShade)); - } - } - } - } - - /** - * Finds mean of per-face shading factors weighted by normal components. - * Not how light actually works but the vanilla diffuse shading model is a hack to start with - * and this gives reasonable results for non-cubic surfaces in a vanilla-style renderer. - */ - private float normalShade(float normalX, float normalY, float normalZ, boolean hasShade) { - float sum = 0; - float div = 0; - - if (normalX > 0) { - sum += normalX * blockInfo.level.getShade(Direction.EAST, hasShade); - div += normalX; - } else if (normalX < 0) { - sum += -normalX * blockInfo.level.getShade(Direction.WEST, hasShade); - div -= normalX; - } - - if (normalY > 0) { - sum += normalY * blockInfo.level.getShade(Direction.UP, hasShade); - div += normalY; - } else if (normalY < 0) { - sum += -normalY * blockInfo.level.getShade(Direction.DOWN, hasShade); - div -= normalY; - } - - if (normalZ > 0) { - sum += normalZ * blockInfo.level.getShade(Direction.SOUTH, hasShade); - div += normalZ; - } else if (normalZ < 0) { - sum += -normalZ * blockInfo.level.getShade(Direction.NORTH, hasShade); - div -= normalZ; - } - - return sum / div; - } - - /** - * Handles geometry-based check for using self light or neighbor light. - * That logic only applies in flat lighting. - */ - private int flatLight(MutableQuadViewImpl quad) { - BlockState blockState = blockInfo.blockState; - BlockPos pos = blockInfo.blockPos; - lightPos.set(pos); - - // To mirror Vanilla's behavior, if the face has a cull-face, always sample the light value - // offset in that direction. See net.minecraft.client.renderer.block.ModelBlockRenderer.renderModelFaceFlat - // for reference. - if (quad.cullFace() != null) { - lightPos.move(quad.cullFace()); - } else { - final int flags = quad.geometryFlags(); - - if ((flags & LIGHT_FACE_FLAG) != 0 || ((flags & AXIS_ALIGNED_FLAG) != 0 && blockState.isCollisionShapeFullBlock(blockInfo.level, pos))) { - lightPos.move(quad.lightFace()); - } - } - - return lightDataProvider.light(lightPos, blockState); - } -} 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 new file mode 100644 index 00000000000..9244da78891 --- /dev/null +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/AltItemRenderer.java @@ -0,0 +1,152 @@ +/* + * 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/AltModelBlockRendererImpl.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/AltModelBlockRendererImpl.java new file mode 100644 index 00000000000..545ebc24fc1 --- /dev/null +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/AltModelBlockRendererImpl.java @@ -0,0 +1,241 @@ +/* + * 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.Predicate; + +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import org.joml.Vector3f; +import org.jspecify.annotations.Nullable; + +import net.minecraft.client.color.block.BlockColors; +import net.minecraft.client.color.block.BlockTintSource; +import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.block.BlockModelLighter; +import net.minecraft.client.renderer.block.dispatch.BlockStateModel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.ARGB; +import net.minecraft.util.LightCoordsUtil; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; + +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.mesh.QuadTransform; +import net.fabricmc.fabric.api.client.renderer.v1.mesh.ShadeMode; +import net.fabricmc.fabric.api.client.renderer.v1.render.AltModelBlockRenderer; +import net.fabricmc.fabric.api.client.renderer.v1.render.ExtraLightCoordsUtil; +import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.AoCalculator; +import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.FlatLighter; +import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl; +import net.fabricmc.fabric.mixin.client.indigo.renderer.BlockModelLighterAccessor; + +public class AltModelBlockRendererImpl implements AltModelBlockRenderer, QuadTransform { + private final boolean ambientOcclusion; + private final boolean cull; + private final BlockColors blockColors; + + private final Predicate<@Nullable Direction> cullTest = this::shouldCullFace; + private final AoCalculator aoCalc; + private final FlatLighter flatLighter; + + private final RandomSource random = RandomSource.createThreadLocalInstance(0L); + private final BlockPos.MutableBlockPos scratchPos = new BlockPos.MutableBlockPos(); + + private int cacheValid; + private int shouldCullFaceCache; + + private int tintCacheIndex = -1; + private int tintCacheValue; + private boolean tintSourcesInitialized; + private final List<@Nullable BlockTintSource> tintSources = new ObjectArrayList<>(); + private final IntList computedTintValues = new IntArrayList(); + + private final Vector3f offset = new Vector3f(); + private BlockAndTintGetter level; + private BlockPos pos; + private BlockState blockState; + private boolean defaultAo; + + public AltModelBlockRendererImpl(boolean ambientOcclusion, boolean cull, BlockColors blockColors) { + this.ambientOcclusion = ambientOcclusion; + this.cull = cull; + this.blockColors = blockColors; + + BlockModelLighter.Cache lightCache = BlockModelLighterAccessor.fabric_getCACHE().get(); + aoCalc = new AoCalculator(lightCache); + flatLighter = new FlatLighter(lightCache); + } + + @Override + public void tesselateBlock(QuadEmitter output, float x, float y, float z, BlockAndTintGetter level, BlockPos pos, BlockState blockState, BlockStateModel model, long seed) { + Vec3 offset = blockState.getOffset(pos); + this.offset.set(x + offset.x, y + offset.y, z + offset.z); + this.level = level; + this.pos = pos; + this.blockState = blockState; + defaultAo = ambientOcclusion && blockState.getLightEmission() == 0; + + cacheValid = 0; + shouldCullFaceCache = 0; + aoCalc.prepare(level, blockState, pos); + + random.setSeed(seed); + output.clear(); + output.pushTransform(this); + + try { + model.emitQuads(output, level, pos, blockState, random, cull ? cullTest : _ -> false); + } finally { + output.popTransform(); + + this.level = null; + aoCalc.clear(); + resetTintCache(); + } + } + + @Override + public boolean transform(MutableQuadView quad) { + if (cull && shouldCullFace(quad.cullFace())) { + return false; + } + + shadeQuad((MutableQuadViewImpl) quad, ambientOcclusion && quad.ambientOcclusion().orElse(defaultAo), quad.emissive(), quad.shadeMode() == ShadeMode.VANILLA); + tintQuad(quad); + quad.translate(offset.x, offset.y, offset.z); + return true; + } + + private boolean shouldCullFace(final @Nullable Direction direction) { + if (direction == null) { + return false; + } + + int cacheMask = 1 << direction.ordinal(); + + if ((cacheValid & cacheMask) == 0) { + cacheValid |= cacheMask; + BlockState neighborState = level.getBlockState(scratchPos.setWithOffset(pos, direction)); + + if (!Block.shouldRenderFace(blockState, neighborState, direction)) { + shouldCullFaceCache |= cacheMask; + return true; + } else { + return false; + } + } else { + return (shouldCullFaceCache & cacheMask) == 1; + } + } + + private void shadeQuad(MutableQuadViewImpl quad, boolean ao, boolean emissive, boolean vanillaShade) { + // routines below have a bit of copy-paste code reuse to avoid conditional execution inside a hot loop + if (ao) { + aoCalc.compute(quad, vanillaShade); + + if (emissive) { + for (int i = 0; i < 4; i++) { + quad.color(i, ARGB.scaleRGB(quad.color(i), aoCalc.ao[i])); + quad.lightmap(i, LightCoordsUtil.FULL_BRIGHT); + } + } else { + for (int i = 0; i < 4; i++) { + quad.color(i, ARGB.scaleRGB(quad.color(i), aoCalc.ao[i])); + quad.lightmap(i, ExtraLightCoordsUtil.smoothMax(quad.lightmap(i), aoCalc.light[i])); + } + } + } else { + if (emissive) { + quad.lightmap(LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT, LightCoordsUtil.FULL_BRIGHT); + } else { + quad.minLightmap(flatLighter.light(level, blockState, pos, quad)); + } + + flatLighter.applyDirectionalBrightness(level.cardinalLighting(), quad, vanillaShade); + } + } + + private void tintQuad(MutableQuadView quad) { + int tintIndex = quad.tintIndex(); + + if (tintIndex != -1) { + quad.multiplyColor(getTintColor(level, blockState, pos, tintIndex)); + } + } + + private void configureTintCache(final BlockState blockState) { + List tintSources = blockColors.getTintSources(blockState); + int tintSourceCount = tintSources.size(); + + if (tintSourceCount > 0) { + this.tintSources.addAll(tintSources); + + for (int i = 0; i < tintSourceCount; ++i) { + computedTintValues.add(-1); + } + } + } + + private int computeTintColor(final BlockAndTintGetter level, final BlockState state, final BlockPos pos, final int tintIndex) { + if (!tintSourcesInitialized) { + configureTintCache(state); + tintSourcesInitialized = true; + } + + if (tintIndex >= tintSources.size()) { + return -1; + } else { + BlockTintSource tintSource = tintSources.set(tintIndex, null); + + if (tintSource != null) { + int computedTintValue = tintSource.colorInWorld(state, level, pos); + computedTintValues.set(tintIndex, computedTintValue); + return computedTintValue; + } else { + return computedTintValues.getInt(tintIndex); + } + } + } + + private int getTintColor(final BlockAndTintGetter level, final BlockState state, final BlockPos pos, final int tintIndex) { + if (tintCacheIndex == tintIndex) { + return tintCacheValue; + } else { + int tintColor = computeTintColor(level, state, pos, tintIndex); + tintCacheIndex = tintIndex; + tintCacheValue = tintColor; + return tintColor; + } + } + + private void resetTintCache() { + tintCacheIndex = -1; + + if (tintSourcesInitialized) { + tintSources.clear(); + computedTintValues.clear(); + tintSourcesInitialized = false; + } + } +} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/BlockRenderInfo.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/BlockRenderInfo.java deleted file mode 100644 index ed1eb2d73e8..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/BlockRenderInfo.java +++ /dev/null @@ -1,114 +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 org.jspecify.annotations.Nullable; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.color.block.BlockColors; -import net.minecraft.client.renderer.ItemBlockRenderTypes; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; - -import net.fabricmc.fabric.api.util.TriState; - -/** - * Holds, manages, and provides access to the block/level related state - * needed to buffer quads. - */ -public class BlockRenderInfo { - private final BlockColors blockColorMap = Minecraft.getInstance().getBlockColors(); - private final BlockPos.MutableBlockPos searchPos = new BlockPos.MutableBlockPos(); - - public BlockAndTintGetter level; - public BlockPos blockPos; - public BlockState blockState; - - private boolean useAo; - private boolean defaultAo; - private ChunkSectionLayer defaultLayer; - - private boolean enableCulling; - private int cullCompletionFlags; - private int cullResultFlags; - - public void prepareForLevel(BlockAndTintGetter level, boolean enableCulling) { - this.level = level; - this.enableCulling = enableCulling; - } - - public void prepareForBlock(BlockPos blockPos, BlockState blockState) { - this.blockPos = blockPos; - this.blockState = blockState; - - useAo = Minecraft.useAmbientOcclusion(); - defaultAo = useAo && blockState.getLightEmission() == 0; - - defaultLayer = ItemBlockRenderTypes.getChunkRenderType(blockState); - - cullCompletionFlags = 0; - cullResultFlags = 0; - } - - public void release() { - level = null; - blockPos = null; - blockState = null; - } - - public int blockColor(int tintIndex) { - return 0xFF000000 | blockColorMap.getColor(blockState, - level, blockPos, tintIndex); - } - - public boolean effectiveAo(TriState aoMode) { - return useAo && aoMode.orElse(defaultAo); - } - - public ChunkSectionLayer effectiveChunkLayer(@Nullable ChunkSectionLayer quadLayer) { - return quadLayer == null ? defaultLayer : quadLayer; - } - - public boolean shouldDrawSide(@Nullable Direction side) { - if (side == null || !enableCulling) { - return true; - } - - final int mask = 1 << side.get3DDataValue(); - - if ((cullCompletionFlags & mask) == 0) { - cullCompletionFlags |= mask; - - if (Block.shouldRenderFace(blockState, level.getBlockState(searchPos.setWithOffset(blockPos, side)), side)) { - cullResultFlags |= mask; - return true; - } else { - return false; - } - } else { - return (cullResultFlags & mask) != 0; - } - } - - public boolean shouldCullSide(@Nullable Direction side) { - return !shouldDrawSide(side); - } -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/ItemRenderContext.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/ItemRenderContext.java deleted file mode 100644 index 21c51fefc5d..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/ItemRenderContext.java +++ /dev/null @@ -1,236 +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.Arrays; -import java.util.List; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.math.MatrixUtil; -import org.jspecify.annotations.Nullable; - -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.Sheets; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; -import net.minecraft.client.renderer.entity.ItemRenderer; -import net.minecraft.client.renderer.item.ItemStackRenderState; -import net.minecraft.client.renderer.rendertype.RenderType; -import net.minecraft.util.ARGB; -import net.minecraft.util.LightCoordsUtil; -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.QuadAtlas; -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.ItemRenderTypeGetter; -import net.fabricmc.fabric.impl.client.indigo.renderer.helper.ColorHelper; -import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl; -import net.fabricmc.fabric.mixin.client.indigo.renderer.ItemRendererAccessor; - -/** - * Used during item buffering to support geometry added through {@link FabricLayerRenderState#emitter()}. - */ -public class ItemRenderContext extends AbstractRenderContext { - private static final int FOIL_TYPE_COUNT = ItemStackRenderState.FoilType.values().length; - - private ItemDisplayContext displayContext; - private MultiBufferSource bufferSource; - private int light; - private int[] tints; - - private RenderType defaultRenderType; - @Nullable - private ItemRenderTypeGetter renderTypeGetter; - private ItemStackRenderState.FoilType defaultFoilType; - private boolean ignoreQuadFoilType; - private boolean translucent; - - private PoseStack.Pose specialFoilPose; - // TODO: reuse this between submits - private final VertexConsumer[] vertexConsumerCache = new VertexConsumer[3 * FOIL_TYPE_COUNT]; - - public void renderItem( - ItemDisplayContext displayContext, - PoseStack poseStack, - MultiBufferSource bufferSource, - int light, - int overlay, - int[] tints, - List vanillaQuads, - MeshView mesh, - RenderType renderType, - @Nullable ItemRenderTypeGetter renderTypeGetter, - ItemStackRenderState.FoilType foilType, - boolean ignoreQuadFoilType, - boolean translucent - ) { - this.displayContext = displayContext; - pose = poseStack.last(); - this.bufferSource = bufferSource; - this.light = light; - this.overlay = overlay; - this.tints = tints; - - defaultRenderType = renderType; - this.renderTypeGetter = renderTypeGetter; - defaultFoilType = foilType; - this.ignoreQuadFoilType = ignoreQuadFoilType; - this.translucent = translucent; - - bufferQuads(vanillaQuads, mesh); - - pose = null; - this.bufferSource = null; - this.tints = null; - - defaultRenderType = null; - this.renderTypeGetter = null; - - specialFoilPose = null; - Arrays.fill(vertexConsumerCache, null); - } - - private void bufferQuads(List vanillaQuads, MeshView mesh) { - QuadEmitter emitter = getEmitter(); - - final int vanillaQuadCount = vanillaQuads.size(); - - for (int i = 0; i < vanillaQuadCount; i++) { - final BakedQuad q = vanillaQuads.get(i); - emitter.fromBakedQuad(q); - emitter.emit(); - } - - mesh.outputTo(emitter); - } - - @Override - protected void bufferQuad(MutableQuadViewImpl quad) { - final RenderType renderType = getRenderType(quad.atlas(), quad.chunkLayer()); - - if (renderType.hasBlending() != translucent) { - return; - } - - final VertexConsumer vertexConsumer = getVertexConsumer(renderType, quad.foilType()); - - tintQuad(quad); - shadeQuad(quad, quad.emissive()); - bufferQuad(quad, vertexConsumer); - } - - private void tintQuad(MutableQuadViewImpl quad) { - int tintIndex = quad.tintIndex(); - - if (tintIndex >= 0 && tintIndex < tints.length) { - final int tint = tints[tintIndex]; - - for (int i = 0; i < 4; i++) { - quad.color(i, ARGB.multiply(quad.color(i), tint)); - } - } - } - - private void shadeQuad(MutableQuadViewImpl quad, boolean emissive) { - if (emissive) { - for (int i = 0; i < 4; i++) { - quad.lightmap(i, LightCoordsUtil.FULL_BRIGHT); - } - } else { - final int light = this.light; - - for (int i = 0; i < 4; i++) { - quad.lightmap(i, ColorHelper.maxLight(quad.lightmap(i), light)); - } - } - } - - private RenderType getRenderType(QuadAtlas quadAtlas, @Nullable ChunkSectionLayer quadLayer) { - RenderType renderType; - - if (renderTypeGetter != null) { - renderType = renderTypeGetter.renderType(quadAtlas, quadLayer); - - if (renderType == null) { - renderType = defaultRenderType; - } - } else { - renderType = defaultRenderType; - } - - return renderType; - } - - private VertexConsumer getVertexConsumer(RenderType renderType, ItemStackRenderState.@Nullable FoilType quadFoilType) { - ItemStackRenderState.FoilType foilType; - - if (ignoreQuadFoilType || quadFoilType == null) { - foilType = defaultFoilType; - } else { - foilType = quadFoilType; - } - - int cacheIndex; - - if (renderType == Sheets.translucentItemSheet()) { - cacheIndex = 0; - } else if (renderType == Sheets.cutoutBlockSheet()) { - cacheIndex = FOIL_TYPE_COUNT; - } else if (renderType == Sheets.translucentBlockItemSheet()) { - cacheIndex = 2 * FOIL_TYPE_COUNT; - } else { - return createVertexConsumer(renderType, foilType); - } - - cacheIndex += foilType.ordinal(); - VertexConsumer vertexConsumer = vertexConsumerCache[cacheIndex]; - - if (vertexConsumer == null) { - vertexConsumer = createVertexConsumer(renderType, foilType); - vertexConsumerCache[cacheIndex] = vertexConsumer; - } - - return vertexConsumer; - } - - private VertexConsumer createVertexConsumer(RenderType renderType, ItemStackRenderState.FoilType foilType) { - if (foilType == ItemStackRenderState.FoilType.SPECIAL) { - if (specialFoilPose == null) { - specialFoilPose = pose.copy(); - - if (displayContext == ItemDisplayContext.GUI) { - MatrixUtil.mulComponentWise(specialFoilPose.pose(), 0.5F); - } else if (displayContext.firstPerson()) { - MatrixUtil.mulComponentWise(specialFoilPose.pose(), 0.75F); - } - } - - return ItemRendererAccessor.fabric_getSpecialFoilBuffer( - bufferSource, - renderType, - specialFoilPose - ); - } - - return ItemRenderer.getFoilBuffer( - bufferSource, - renderType, true, foilType != ItemStackRenderState.FoilType.NONE); - } -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/LightDataProvider.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/LightDataProvider.java deleted file mode 100644 index 574b510c6e9..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/LightDataProvider.java +++ /dev/null @@ -1,26 +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.core.BlockPos; -import net.minecraft.world.level.block.state.BlockState; - -public interface LightDataProvider { - int light(BlockPos pos, BlockState state); - - float ao(BlockPos pos, BlockState state); -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/MeshItemSubmit.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/MeshItemSubmit.java deleted file mode 100644 index a356d22e1d2..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/MeshItemSubmit.java +++ /dev/null @@ -1,45 +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 org.jspecify.annotations.Nullable; - -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.item.ItemStackRenderState; -import net.minecraft.client.renderer.rendertype.RenderType; -import net.minecraft.world.item.ItemDisplayContext; - -import net.fabricmc.fabric.api.client.renderer.v1.mesh.MeshView; -import net.fabricmc.fabric.api.client.renderer.v1.render.ItemRenderTypeGetter; - -public record MeshItemSubmit( - PoseStack.Pose pose, - ItemDisplayContext displayContext, - int lightCoords, - int overlayCoords, - int outlineColor, - int[] tintLayers, - List quads, - RenderType renderType, - ItemStackRenderState.FoilType foilType, - MeshView mesh, - @Nullable ItemRenderTypeGetter renderTypeGetter -) { -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/SimpleBlockRenderContext.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/SimpleBlockRenderContext.java deleted file mode 100644 index 4df19dc27da..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/SimpleBlockRenderContext.java +++ /dev/null @@ -1,130 +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.function.Predicate; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import org.jspecify.annotations.Nullable; - -import net.minecraft.client.renderer.ItemBlockRenderTypes; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; -import net.minecraft.core.BlockPos; -import net.minecraft.util.ARGB; -import net.minecraft.util.LightCoordsUtil; -import net.minecraft.util.Mth; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; - -import net.fabricmc.fabric.api.client.renderer.v1.render.BlockMultiBufferSource; -import net.fabricmc.fabric.impl.client.indigo.renderer.helper.ColorHelper; -import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl; - -public class SimpleBlockRenderContext extends AbstractRenderContext { - public static final ThreadLocal POOL = ThreadLocal.withInitial(SimpleBlockRenderContext::new); - - private final RandomSource random = RandomSource.createNewThreadLocalInstance(); - - private BlockMultiBufferSource bufferSource; - @Nullable - private Predicate layerFilter; - private ChunkSectionLayer defaultChunkLayer; - private float red; - private float green; - private float blue; - private int light; - - @Nullable - private ChunkSectionLayer lastChunkLayer; - @Nullable - private VertexConsumer lastVertexConsumer; - - @Override - protected void bufferQuad(MutableQuadViewImpl quad) { - final ChunkSectionLayer quadLayer = quad.chunkLayer(); - final ChunkSectionLayer layer = quadLayer == null ? defaultChunkLayer : quadLayer; - - if (layerFilter != null && !layerFilter.test(layer)) { - return; - } - - final VertexConsumer vertexConsumer; - - if (layer == lastChunkLayer) { - vertexConsumer = lastVertexConsumer; - } else { - lastVertexConsumer = vertexConsumer = bufferSource.getBuffer(layer); - lastChunkLayer = layer; - } - - tintQuad(quad); - shadeQuad(quad, quad.emissive()); - bufferQuad(quad, vertexConsumer); - } - - private void tintQuad(MutableQuadViewImpl quad) { - if (quad.tintIndex() != -1) { - final float red = this.red; - final float green = this.green; - final float blue = this.blue; - - for (int i = 0; i < 4; i++) { - quad.color(i, ARGB.scaleRGB(quad.color(i), red, green, blue)); - } - } - } - - private void shadeQuad(MutableQuadViewImpl quad, boolean emissive) { - if (emissive) { - for (int i = 0; i < 4; i++) { - quad.lightmap(i, LightCoordsUtil.FULL_BRIGHT); - } - } else { - final int light = this.light; - - for (int i = 0; i < 4; i++) { - quad.lightmap(i, ColorHelper.maxLight(quad.lightmap(i), light)); - } - } - } - - public void bufferModel(PoseStack.Pose pose, BlockMultiBufferSource bufferSource, @Nullable Predicate layerFilter, BlockStateModel model, float red, float green, float blue, int light, int overlay, BlockAndTintGetter level, BlockPos pos, BlockState state) { - this.pose = pose; - this.overlay = overlay; - - this.bufferSource = bufferSource; - this.layerFilter = layerFilter; - this.defaultChunkLayer = ItemBlockRenderTypes.getChunkRenderType(state); - this.red = Mth.clamp(red, 0, 1); - this.green = Mth.clamp(green, 0, 1); - this.blue = Mth.clamp(blue, 0, 1); - this.light = light; - - random.setSeed(42L); - - model.emitQuads(getEmitter(), level, pos, state, random, _ -> false); - - this.pose = null; - this.bufferSource = null; - this.layerFilter = null; - lastChunkLayer = null; - lastVertexConsumer = null; - } -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/TerrainLikeRenderContext.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/TerrainLikeRenderContext.java deleted file mode 100644 index 69d24289938..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/TerrainLikeRenderContext.java +++ /dev/null @@ -1,106 +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.function.Predicate; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import org.jspecify.annotations.Nullable; - -import net.minecraft.CrashReport; -import net.minecraft.CrashReportCategory; -import net.minecraft.ReportedException; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; -import net.minecraft.core.BlockPos; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -import net.fabricmc.fabric.api.client.renderer.v1.render.BlockMultiBufferSource; -import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.AoLuminanceFix; - -/** - * Used during terrain-like block buffering to invoke {@link BlockStateModel#emitQuads}. - */ -public class TerrainLikeRenderContext extends AbstractTerrainRenderContext { - public static final ThreadLocal POOL = ThreadLocal.withInitial(TerrainLikeRenderContext::new); - - private final RandomSource random = RandomSource.createNewThreadLocalInstance(); - - private BlockMultiBufferSource bufferSource; - @Nullable - private Predicate layerFilter; - - @Override - protected LightDataProvider createLightDataProvider(BlockRenderInfo blockInfo) { - // TODO: Use a cache whenever vanilla would use a cache (BrightnessCache.enabled) - return new LightDataProvider() { - @Override - public int light(BlockPos pos, BlockState state) { - return LevelRenderer.getLightCoords(LevelRenderer.BrightnessGetter.DEFAULT, blockInfo.level, state, pos); - } - - @Override - public float ao(BlockPos pos, BlockState state) { - return AoLuminanceFix.INSTANCE.apply(blockInfo.level, pos, state); - } - }; - } - - @Override - @Nullable - protected VertexConsumer getVertexConsumer(ChunkSectionLayer layer) { - if (layerFilter != null && !layerFilter.test(layer)) { - return null; - } - - return bufferSource.getBuffer(layer); - } - - public void bufferModel(BlockAndTintGetter level, BlockStateModel model, BlockState state, BlockPos pos, PoseStack poseStack, BlockMultiBufferSource bufferSource, @Nullable Predicate layerFilter, boolean cull, long seed, int overlay) { - try { - Vec3 offset = state.getOffset(pos); - poseStack.translate(offset.x, offset.y, offset.z); - pose = poseStack.last(); - this.overlay = overlay; - - this.bufferSource = bufferSource; - this.layerFilter = layerFilter; - - blockInfo.prepareForLevel(level, cull); - random.setSeed(seed); - - prepare(pos, state); - model.emitQuads(getEmitter(), level, pos, state, random, blockInfo::shouldCullSide); - } catch (Throwable throwable) { - CrashReport crashReport = CrashReport.forThrowable(throwable, "Tessellating block model - Indigo Renderer"); - CrashReportCategory crashReportCategory = crashReport.addCategory("Block model being tessellated"); - CrashReportCategory.populateBlockDetails(crashReportCategory, - level, pos, state); - throw new ReportedException(crashReport); - } finally { - blockInfo.release(); - pose = null; - this.bufferSource = null; - this.layerFilter = null; - } - } -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/TerrainRenderContext.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/TerrainRenderContext.java deleted file mode 100644 index f2b9c678eda..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/TerrainRenderContext.java +++ /dev/null @@ -1,194 +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.Arrays; -import java.util.function.Function; - -import com.mojang.blaze3d.vertex.BufferBuilder; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import org.jspecify.annotations.NonNull; - -import net.minecraft.CrashReport; -import net.minecraft.CrashReportCategory; -import net.minecraft.ReportedException; -import net.minecraft.client.renderer.LevelRenderer; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; -import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.core.BlockPos; -import net.minecraft.core.SectionPos; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.Vec3; - -import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.AoLuminanceFix; - -/** - * Used during section block buffering to invoke {@link BlockStateModel#emitQuads}. - */ -public class TerrainRenderContext extends AbstractTerrainRenderContext { - public static final ThreadLocal POOL = ThreadLocal.withInitial(TerrainRenderContext::new); - - private PoseStack poseStack; - private RandomSource random; - private Function bufferFunc; - - public TerrainRenderContext() { - overlay = OverlayTexture.NO_OVERLAY; - } - - @Override - protected LightDataProvider createLightDataProvider(BlockRenderInfo blockInfo) { - return new LightDataCache(blockInfo); - } - - @Override - @NonNull - protected VertexConsumer getVertexConsumer(ChunkSectionLayer layer) { - return bufferFunc.apply(layer); - } - - public void prepare(BlockAndTintGetter level, BlockPos sectionOrigin, PoseStack poseStack, RandomSource random, Function bufferFunc) { - blockInfo.prepareForLevel(level, true); - ((LightDataCache) lightDataProvider).prepare(sectionOrigin); - - this.poseStack = poseStack; - this.random = random; - this.bufferFunc = bufferFunc; - } - - public void release() { - pose = null; - poseStack = null; - random = null; - bufferFunc = null; - - blockInfo.release(); - } - - /** Called from section compiler hook. */ - public void bufferModel(BlockStateModel model, BlockState blockState, BlockPos blockPos) { - poseStack.pushPose(); - - try { - poseStack.translate(SectionPos.sectionRelative(blockPos.getX()), SectionPos.sectionRelative(blockPos.getY()), SectionPos.sectionRelative(blockPos.getZ())); - Vec3 offset = blockState.getOffset(blockPos); - poseStack.translate(offset.x, offset.y, offset.z); - pose = poseStack.last(); - - random.setSeed(blockState.getSeed(blockPos)); - - prepare(blockPos, blockState); - model.emitQuads(getEmitter(), blockInfo.level, blockPos, blockState, random, blockInfo::shouldCullSide); - } catch (Throwable throwable) { - CrashReport crashReport = CrashReport.forThrowable(throwable, "Tessellating block in world - Indigo Renderer"); - CrashReportCategory crashReportCategory = crashReport.addCategory("Block being tessellated"); - CrashReportCategory.populateBlockDetails(crashReportCategory, blockInfo.level, blockPos, blockState); - throw new ReportedException(crashReport); - } finally { - poseStack.popPose(); - } - } - - private static class LightDataCache implements LightDataProvider { - // Since this context is only used during section building, we know ahead of time all positions for which data - // may be requested by flat or smooth lighting, so we use an array instead of a map to cache that data, unlike - // vanilla. Even though cache indices are positions and therefore 3D, the cache is 1D to maximize memory - // locality. - private final int[] lightCache = new int[18 * 18 * 18]; - private final float[] aoCache = new float[18 * 18 * 18]; - - private final BlockRenderInfo blockInfo; - private BlockPos sectionOrigin; - - LightDataCache(BlockRenderInfo blockInfo) { - this.blockInfo = blockInfo; - } - - private final LevelRenderer.BrightnessGetter brightnessGetter = (level, pos) -> { - int cacheIndex = cacheIndex(pos); - - if (cacheIndex == -1) { - return LevelRenderer.BrightnessGetter.DEFAULT.packedBrightness(level, pos); - } - - int result = lightCache[cacheIndex]; - - if (result == Integer.MAX_VALUE) { - result = LevelRenderer.BrightnessGetter.DEFAULT.packedBrightness(level, pos); - lightCache[cacheIndex] = result; - } - - return result; - }; - - public void prepare(BlockPos sectionOrigin) { - this.sectionOrigin = sectionOrigin; - - Arrays.fill(lightCache, Integer.MAX_VALUE); - Arrays.fill(aoCache, Float.NaN); - } - - @Override - public int light(BlockPos pos, BlockState state) { - return LevelRenderer.getLightCoords(brightnessGetter, blockInfo.level, state, pos); - } - - @Override - public float ao(BlockPos pos, BlockState state) { - int cacheIndex = cacheIndex(pos); - - if (cacheIndex == -1) { - return AoLuminanceFix.INSTANCE.apply(blockInfo.level, pos, state); - } - - float result = aoCache[cacheIndex]; - - if (Float.isNaN(result)) { - result = AoLuminanceFix.INSTANCE.apply(blockInfo.level, pos, state); - aoCache[cacheIndex] = result; - } - - return result; - } - - private int cacheIndex(BlockPos pos) { - int localX = pos.getX() - (sectionOrigin.getX() - 1); - - if (localX < 0 || localX >= 18) { - return -1; - } - - int localY = pos.getY() - (sectionOrigin.getY() - 1); - - if (localY < 0 || localY >= 18) { - return -1; - } - - int localZ = pos.getZ() - (sectionOrigin.getZ() - 1); - - if (localZ < 0 || localZ >= 18) { - return -1; - } - - return localZ * 18 * 18 + localY * 18 + localX; - } - } -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/BlockRenderDispatcherAccessor.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/BlockModelLighterAccessor.java similarity index 74% rename from fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/BlockRenderDispatcherAccessor.java rename to fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/BlockModelLighterAccessor.java index 2f48ea76688..763d97c2ba4 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/BlockRenderDispatcherAccessor.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/BlockModelLighterAccessor.java @@ -19,11 +19,12 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -import net.minecraft.client.color.block.BlockColors; -import net.minecraft.client.renderer.block.BlockRenderDispatcher; +import net.minecraft.client.renderer.block.BlockModelLighter; -@Mixin(BlockRenderDispatcher.class) -public interface BlockRenderDispatcherAccessor { - @Accessor("blockColors") - BlockColors getBlockColors(); +@Mixin(BlockModelLighter.class) +public interface BlockModelLighterAccessor { + @Accessor("CACHE") + static ThreadLocal fabric_getCACHE() { + throw new AssertionError(); + } } diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/BlockRenderDispatcherMixin.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/BlockRenderDispatcherMixin.java deleted file mode 100644 index 45dc68bac10..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/BlockRenderDispatcherMixin.java +++ /dev/null @@ -1,61 +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 com.llamalad7.mixinextras.sugar.Local; -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.renderer.MultiBufferSource; -import net.minecraft.client.renderer.block.BlockRenderDispatcher; -import net.minecraft.client.renderer.block.ModelBlockRenderer; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.EmptyBlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; - -import net.fabricmc.fabric.api.client.renderer.v1.render.ChunkSectionLayerHelper; -import net.fabricmc.fabric.api.client.renderer.v1.render.FabricModelBlockRenderer; - -@Mixin(BlockRenderDispatcher.class) -abstract class BlockRenderDispatcherMixin { - @Shadow - @Final - private ModelBlockRenderer modelRenderer; - - @Inject(method = "renderBreakingTexture(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/BlockAndTintGetter;Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;)V", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/client/renderer/block/BlockModelShaper;getBlockModel(Lnet/minecraft/world/level/block/state/BlockState;)Lnet/minecraft/client/renderer/block/model/BlockStateModel;"), cancellable = true) - private void afterGetModel(BlockState blockState, BlockPos blockPos, BlockAndTintGetter level, PoseStack poseStack, VertexConsumer vertexConsumer, CallbackInfo ci, @Local(name = "model") BlockStateModel model) { - modelRenderer.tesselateBlock(level, model, blockState, blockPos, - poseStack, layer -> vertexConsumer, true, blockState.getSeed(blockPos), OverlayTexture.NO_OVERLAY); - ci.cancel(); - } - - @Redirect(method = "renderSingleBlock(Lnet/minecraft/world/level/block/state/BlockState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;II)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/block/ModelBlockRenderer;renderModel(Lcom/mojang/blaze3d/vertex/PoseStack$Pose;Lcom/mojang/blaze3d/vertex/VertexConsumer;Lnet/minecraft/client/renderer/block/model/BlockStateModel;FFFII)V")) - private void renderProxy(PoseStack.Pose pose, VertexConsumer vertexConsumer, BlockStateModel model, float red, float green, float blue, int light, int overlay, BlockState state, PoseStack poseStack, MultiBufferSource bufferSource, int light1, int overlay1) { - FabricModelBlockRenderer.renderModel(pose, ChunkSectionLayerHelper.entityDelegate( - bufferSource), model, red, green, blue, light, overlay, EmptyBlockAndTintGetter.INSTANCE, BlockPos.ZERO, state); - } -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemRendererAccessor.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemFeatureRendererAccessor.java similarity index 63% rename from fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemRendererAccessor.java rename to fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemFeatureRendererAccessor.java index 5437cf6666b..3880bd58c02 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemRendererAccessor.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemFeatureRendererAccessor.java @@ -18,17 +18,24 @@ 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.entity.ItemRenderer; +import net.minecraft.client.renderer.feature.ItemFeatureRenderer; import net.minecraft.client.renderer.rendertype.RenderType; +import net.minecraft.world.item.ItemDisplayContext; -@Mixin(ItemRenderer.class) -public interface ItemRendererAccessor { - @Invoker("getSpecialFoilBuffer") - static VertexConsumer fabric_getSpecialFoilBuffer(MultiBufferSource bufferSource, RenderType renderType, PoseStack.Pose pose) { +@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(); } } 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 index d4203d5f817..94de5914d04 100644 --- 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 @@ -16,10 +16,7 @@ package net.fabricmc.fabric.mixin.client.indigo.renderer; -import com.mojang.blaze3d.vertex.PoseStack; -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; @@ -29,108 +26,34 @@ import net.minecraft.client.renderer.OutlineBufferSource; import net.minecraft.client.renderer.SubmitNodeCollection; import net.minecraft.client.renderer.feature.ItemFeatureRenderer; -import net.minecraft.client.renderer.item.ItemStackRenderState; -import net.fabricmc.fabric.impl.client.indigo.renderer.accessor.AccessSubmitNodeCollection; -import net.fabricmc.fabric.impl.client.indigo.renderer.render.ItemRenderContext; -import net.fabricmc.fabric.impl.client.indigo.renderer.render.MeshItemSubmit; +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 { - @Shadow - @Final - private PoseStack poseStack; - @Unique - private final ItemRenderContext itemRenderContext = new ItemRenderContext(); + private final AltItemRenderer altItemRenderer = new AltItemRenderer(); @Inject(method = "renderSolid", at = @At("RETURN")) private void onReturnRenderSolid(SubmitNodeCollection nodeCollection, MultiBufferSource.BufferSource bufferSource, OutlineBufferSource outlineBufferSource, CallbackInfo ci) { - for (MeshItemSubmit submit : ((AccessSubmitNodeCollection) nodeCollection).fabric_getMeshItemSubmits()) { - poseStack.pushPose(); - poseStack.last().set(submit.pose()); - - itemRenderContext.renderItem( - submit.displayContext(), - poseStack, - bufferSource, - submit.lightCoords(), - submit.overlayCoords(), - submit.tintLayers(), - submit.quads(), - submit.mesh(), - submit.renderType(), - submit.renderTypeGetter(), - submit.foilType(), - false, - false - ); + altItemRenderer.prepare(bufferSource, outlineBufferSource, false); - if (submit.outlineColor() != 0) { - outlineBufferSource.setColor(submit.outlineColor()); - itemRenderContext.renderItem( - submit.displayContext(), - poseStack, - outlineBufferSource, - submit.lightCoords(), - submit.overlayCoords(), - submit.tintLayers(), - submit.quads(), - submit.mesh(), - submit.renderType(), - submit.renderTypeGetter(), - ItemStackRenderState.FoilType.NONE, - true, - false - ); - } - - poseStack.popPose(); + for (FabricSubmitNodeCollection.ExtendedItemSubmit submit : nodeCollection.getExtendedItemSubmits()) { + altItemRenderer.renderItem(submit); } + + altItemRenderer.clear(); } @Inject(method = "renderTranslucent", at = @At("RETURN")) private void onReturnRenderTranslucent(SubmitNodeCollection nodeCollection, MultiBufferSource.BufferSource bufferSource, OutlineBufferSource outlineBufferSource, CallbackInfo ci) { - for (MeshItemSubmit submit : ((AccessSubmitNodeCollection) nodeCollection).fabric_getMeshItemSubmits()) { - poseStack.pushPose(); - poseStack.last().set(submit.pose()); + altItemRenderer.prepare(bufferSource, outlineBufferSource, true); - itemRenderContext.renderItem( - submit.displayContext(), - poseStack, - bufferSource, - submit.lightCoords(), - submit.overlayCoords(), - submit.tintLayers(), - submit.quads(), - submit.mesh(), - submit.renderType(), - submit.renderTypeGetter(), - submit.foilType(), - false, - true - ); - - if (submit.outlineColor() != 0) { - outlineBufferSource.setColor(submit.outlineColor()); - itemRenderContext.renderItem( - submit.displayContext(), - poseStack, - outlineBufferSource, - submit.lightCoords(), - submit.overlayCoords(), - submit.tintLayers(), - submit.quads(), - submit.mesh(), - submit.renderType(), - submit.renderTypeGetter(), - ItemStackRenderState.FoilType.NONE, - true, - true - ); - } - - poseStack.popPose(); + for (FabricSubmitNodeCollection.ExtendedItemSubmit submit : nodeCollection.getExtendedItemSubmits()) { + altItemRenderer.renderItem(submit); } + + altItemRenderer.clear(); } } diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemStackRenderStateLayerRenderStateMixin.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemStackRenderStateLayerRenderStateMixin.java deleted file mode 100644 index 92d79a98458..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ItemStackRenderStateLayerRenderStateMixin.java +++ /dev/null @@ -1,79 +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 java.util.List; - -import com.mojang.blaze3d.vertex.PoseStack; -import org.jspecify.annotations.Nullable; -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.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.minecraft.client.renderer.SubmitNodeCollector; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.item.ItemStackRenderState; -import net.minecraft.client.renderer.rendertype.RenderType; -import net.minecraft.world.item.ItemDisplayContext; - -import net.fabricmc.fabric.api.client.renderer.v1.render.FabricLayerRenderState; -import net.fabricmc.fabric.api.client.renderer.v1.render.ItemRenderTypeGetter; -import net.fabricmc.fabric.impl.client.indigo.renderer.accessor.AccessLayerRenderState; -import net.fabricmc.fabric.impl.client.indigo.renderer.accessor.AccessOrderedSubmitNodeCollector; -import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableMeshImpl; - -@Mixin(value = ItemStackRenderState.LayerRenderState.class) -abstract class ItemStackRenderStateLayerRenderStateMixin implements FabricLayerRenderState, AccessLayerRenderState { - @Unique - private final MutableMeshImpl mutableMesh = new MutableMeshImpl(); - - @Unique - @Nullable - private ItemRenderTypeGetter renderTypeGetter = null; - - @Inject(method = "clear()V", at = @At("RETURN")) - private void onReturnClear(CallbackInfo ci) { - mutableMesh.clear(); - renderTypeGetter = null; - } - - @Redirect(method = "submit", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/SubmitNodeCollector;submitItem(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/world/item/ItemDisplayContext;III[ILjava/util/List;Lnet/minecraft/client/renderer/rendertype/RenderType;Lnet/minecraft/client/renderer/item/ItemStackRenderState$FoilType;)V")) - private void submitItemProxy(SubmitNodeCollector submitNodeCollector, PoseStack poseStack, ItemDisplayContext displayContext, int light, int overlay, int outlineColor, int[] tints, List quads, RenderType layer, ItemStackRenderState.FoilType foilType) { - if (mutableMesh.size() > 0 && submitNodeCollector instanceof AccessOrderedSubmitNodeCollector access) { - // We don't have to copy the mesh here because vanilla doesn't copy the tint array or quad list either. - access.fabric_submitItem(poseStack, displayContext, light, overlay, outlineColor, tints, quads, layer, - foilType, mutableMesh, renderTypeGetter); - } else { - submitNodeCollector.submitItem(poseStack, displayContext, light, overlay, outlineColor, tints, quads, layer, - foilType - ); - } - } - - @Override - public MutableMeshImpl fabric_getMutableMesh() { - return mutableMesh; - } - - @Override - public void fabric_setRenderTypeGetter(ItemRenderTypeGetter renderTypeGetter) { - this.renderTypeGetter = renderTypeGetter; - } -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ModelBlockRendererMixin.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ModelBlockRendererMixin.java deleted file mode 100644 index fe643016d90..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/ModelBlockRendererMixin.java +++ /dev/null @@ -1,38 +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 com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; - -import net.minecraft.client.renderer.block.ModelBlockRenderer; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.EmptyBlockAndTintGetter; -import net.minecraft.world.level.block.Blocks; - -import net.fabricmc.fabric.api.client.renderer.v1.render.FabricModelBlockRenderer; - -@Mixin(ModelBlockRenderer.class) -abstract class ModelBlockRendererMixin { - @Overwrite - public static void renderModel(PoseStack.Pose pose, VertexConsumer vertexConsumer, BlockStateModel model, float red, float green, float blue, int light, int overlay) { - FabricModelBlockRenderer.renderModel(pose, layer -> vertexConsumer, model, red, green, blue, light, overlay, EmptyBlockAndTintGetter.INSTANCE, BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - } -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/RenderSectionRegionMixin.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/RenderSectionRegionMixin.java deleted file mode 100644 index 951c65533d7..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/RenderSectionRegionMixin.java +++ /dev/null @@ -1,41 +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 net.minecraft.client.renderer.chunk.RenderSectionRegion; - -import net.fabricmc.fabric.impl.client.indigo.renderer.accessor.AccessRenderSectionRegion; -import net.fabricmc.fabric.impl.client.indigo.renderer.render.TerrainRenderContext; - -@Mixin(RenderSectionRegion.class) -abstract class RenderSectionRegionMixin implements AccessRenderSectionRegion { - @Unique - private TerrainRenderContext fabric_renderer; - - @Override - public TerrainRenderContext fabric_getRenderer() { - return fabric_renderer; - } - - @Override - public void fabric_setRenderer(TerrainRenderContext renderer) { - fabric_renderer = renderer; - } -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/SectionCompilerMixin.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/SectionCompilerMixin.java deleted file mode 100644 index 9705878dfe3..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/SectionCompilerMixin.java +++ /dev/null @@ -1,131 +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 java.util.List; -import java.util.Map; - -import com.llamalad7.mixinextras.sugar.Local; -import com.mojang.blaze3d.vertex.BufferBuilder; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.blaze3d.vertex.VertexSorting; -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.CallbackInfoReturnable; - -import net.minecraft.client.renderer.SectionBufferBuilderPack; -import net.minecraft.client.renderer.block.BlockRenderDispatcher; -import net.minecraft.client.renderer.block.model.BlockStateModel; -import net.minecraft.client.renderer.chunk.ChunkSectionLayer; -import net.minecraft.client.renderer.chunk.RenderSectionRegion; -import net.minecraft.client.renderer.chunk.SectionCompiler; -import net.minecraft.core.BlockPos; -import net.minecraft.core.SectionPos; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.RenderShape; -import net.minecraft.world.level.block.state.BlockState; - -import net.fabricmc.fabric.impl.client.indigo.renderer.accessor.AccessRenderSectionRegion; -import net.fabricmc.fabric.impl.client.indigo.renderer.render.TerrainRenderContext; - -/** - * Implements the main hooks for terrain rendering. Attempts to tread - * lightly. This means we are deliberately stepping over some minor - * optimization opportunities. - * - *

Non-Fabric renderer implementations that are looking to maximize - * performance will likely take a much more aggressive approach. - * For that reason, mod authors who want compatibility with advanced - * renderers will do well to steer clear of chunk rebuild hooks unless - * they are creating a renderer. - * - *

These hooks are intended only for the Fabric default renderer and - * aren't expected to be present when a different renderer is being used. - * Renderer authors are responsible for creating the hooks they need. - * (Though they can use these as an example if they wish.) - */ -@Mixin(SectionCompiler.class) -abstract class SectionCompilerMixin { - @Shadow - @Final - private BlockRenderDispatcher blockRenderer; - - @Shadow - protected abstract BufferBuilder getOrBeginLayer( - Map builders, - SectionBufferBuilderPack buffers, - ChunkSectionLayer layer - ); - - @Inject(method = "compile", - at = @At(value = "INVOKE", target = "Lnet/minecraft/core/BlockPos;betweenClosed(Lnet/minecraft/core/BlockPos;Lnet/minecraft/core/BlockPos;)Ljava/lang/Iterable;")) - private void hookBuild(SectionPos sectionPos, RenderSectionRegion region, VertexSorting sorter, - SectionBufferBuilderPack buffers, - CallbackInfoReturnable cir, - @Local(name = "minPos") BlockPos minPos, - @Local(name = "poseStack") PoseStack poseStack, - @Local(name = "startedLayers") Map startedLayers, - @Local(name = "random") RandomSource random) { - // hook just before iterating over the render chunk's blocks to capture the buffer builder map - TerrainRenderContext renderer = TerrainRenderContext.POOL.get(); - renderer.prepare(region, minPos, - poseStack, random, layer -> getOrBeginLayer(startedLayers, - buffers, layer)); - ((AccessRenderSectionRegion) region).fabric_setRenderer(renderer); - } - - /** - * This is the hook that actually implements the rendering API for terrain rendering. - * - *

It's unusual to have a @Redirect in a Fabric library, but in this case it is our explicit intention that - * {@link BlockStateModel#collectParts(RandomSource, List)} and - * {@link BlockRenderDispatcher#renderBatched(BlockState, BlockPos, BlockAndTintGetter, PoseStack, VertexConsumer, boolean, List)} - * do not execute for models that will be rendered by our renderer. For performance and convenience, just skip the - * entire if block. - * - *

Any mod that wants to redirect this specific call is likely also a renderer, in which case this - * renderer should not be present, or the mod should probably instead be relying on the renderer API - * which was specifically created to provide for enhanced terrain rendering. - */ - @Redirect(method = "compile", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;getRenderShape()Lnet/minecraft/world/level/block/RenderShape;")) - private RenderShape hookBuildRenderBlock(BlockState blockState, SectionPos sectionPos, RenderSectionRegion renderRegion, VertexSorting vertexSorter, SectionBufferBuilderPack buffers, @Local(name = "pos") BlockPos pos) { - RenderShape renderShape = blockState.getRenderShape(); - - if (renderShape == RenderShape.MODEL) { - BlockStateModel model = blockRenderer.getBlockModel(blockState); - ((AccessRenderSectionRegion) renderRegion).fabric_getRenderer().bufferModel(model, blockState, pos); - return RenderShape.INVISIBLE; // Cancel the vanilla logic - } - - return renderShape; - } - - /** - * Release all references. Probably not necessary but would be $#%! to debug if it is. - */ - @Inject(method = "compile", at = @At(value = "RETURN")) - private void hookBuildReturn(SectionPos sectionPos, RenderSectionRegion renderRegion, VertexSorting vertexSorter, SectionBufferBuilderPack buffers, CallbackInfoReturnable cir) { - ((AccessRenderSectionRegion) renderRegion).fabric_getRenderer().release(); - ((AccessRenderSectionRegion) renderRegion).fabric_setRenderer(null); - } -} diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/SubmitNodeCollectionMixin.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/SubmitNodeCollectionMixin.java deleted file mode 100644 index 6895cecd5ef..00000000000 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/mixin/client/indigo/renderer/SubmitNodeCollectionMixin.java +++ /dev/null @@ -1,91 +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 java.util.ArrayList; -import java.util.List; - -import com.mojang.blaze3d.vertex.PoseStack; -import org.jspecify.annotations.Nullable; -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.OrderedSubmitNodeCollector; -import net.minecraft.client.renderer.SubmitNodeCollection; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.item.ItemStackRenderState; -import net.minecraft.client.renderer.rendertype.RenderType; -import net.minecraft.world.item.ItemDisplayContext; - -import net.fabricmc.fabric.api.client.renderer.v1.mesh.MeshView; -import net.fabricmc.fabric.api.client.renderer.v1.render.ItemRenderTypeGetter; -import net.fabricmc.fabric.impl.client.indigo.renderer.accessor.AccessOrderedSubmitNodeCollector; -import net.fabricmc.fabric.impl.client.indigo.renderer.accessor.AccessSubmitNodeCollection; -import net.fabricmc.fabric.impl.client.indigo.renderer.render.MeshItemSubmit; - -@Mixin(SubmitNodeCollection.class) -abstract class SubmitNodeCollectionMixin implements OrderedSubmitNodeCollector, AccessOrderedSubmitNodeCollector, AccessSubmitNodeCollection { - @Shadow - private boolean wasUsed; - - @Unique - private final List meshItemSubmits = new ArrayList<>(); - - @Inject(method = "clear()V", at = @At("RETURN")) - public void clear(CallbackInfo ci) { - meshItemSubmits.clear(); - } - - @Override - public void fabric_submitItem( - PoseStack poseStack, - ItemDisplayContext displayContext, - int light, - int overlay, - int outlineColors, - int[] tintLayers, - List quads, - RenderType renderType, - ItemStackRenderState.FoilType foilType, - MeshView mesh, - @Nullable ItemRenderTypeGetter renderTypeGetter - ) { - wasUsed = true; - meshItemSubmits.add(new MeshItemSubmit( - poseStack.last().copy(), - displayContext, - light, - overlay, - outlineColors, - tintLayers, - quads, - renderType, - foilType, - mesh, - renderTypeGetter - )); - } - - @Override - public List fabric_getMeshItemSubmits() { - return meshItemSubmits; - } -} diff --git a/fabric-renderer-indigo/src/client/resources/fabric-renderer-indigo.classtweaker b/fabric-renderer-indigo/src/client/resources/fabric-renderer-indigo.classtweaker index 14d8109ed98..b9feac6efed 100644 --- a/fabric-renderer-indigo/src/client/resources/fabric-renderer-indigo.classtweaker +++ b/fabric-renderer-indigo/src/client/resources/fabric-renderer-indigo.classtweaker @@ -1,4 +1,4 @@ classTweaker v1 official -accessible class net/minecraft/client/renderer/block/ModelBlockRenderer$CommonRenderStorage -accessible class net/minecraft/client/renderer/block/ModelBlockRenderer$AmbientOcclusionRenderStorage -accessible method net/minecraft/client/renderer/block/ModelBlockRenderer calculateShape (Lnet/minecraft/world/level/BlockAndTintGetter;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lnet/minecraft/client/renderer/block/model/BakedQuad;Lnet/minecraft/client/renderer/block/ModelBlockRenderer$CommonRenderStorage;)V +#accessible class net/minecraft/client/renderer/block/ModelBlockRenderer$CommonRenderStorage +#accessible class net/minecraft/client/renderer/block/ModelBlockRenderer$AmbientOcclusionRenderStorage +#accessible method net/minecraft/client/renderer/block/ModelBlockRenderer calculateShape (Lnet/minecraft/world/level/BlockAndTintGetter;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lnet/minecraft/client/renderer/block/model/BakedQuad;Lnet/minecraft/client/renderer/block/ModelBlockRenderer$CommonRenderStorage;)V 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 9c8485c1b8d..90b0804e1e6 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 @@ -4,22 +4,17 @@ "compatibilityLevel": "JAVA_25", "plugin": "net.fabricmc.fabric.impl.client.indigo.IndigoMixinConfigPlugin", "client": [ - "SubmitNodeCollectionMixin", - "ModelBlockRendererMixin", - "BlockRenderDispatcherAccessor", - "BlockRenderDispatcherMixin", - "RenderSectionRegionMixin", - "ItemFeatureRendererMixin", - "ItemRendererAccessor", - "ItemStackRenderStateLayerRenderStateMixin", - "ItemStackRenderStateMixin", - "SubmitNodeStorageMixin", - "SectionCompilerMixin" + "BlockModelLighterAccessor", + "ItemFeatureRendererAccessor", + "ItemFeatureRendererMixin" ], "injectors": { "defaultRequire": 1 }, "overwrites": { "requireAnnotations": true + }, + "mixinextras": { + "minVersion": "0.5.0" } } diff --git a/fabric-renderer-indigo/src/client/resources/fabric.mod.json b/fabric-renderer-indigo/src/client/resources/fabric.mod.json index 0293b0797f9..6b30026f338 100644 --- a/fabric-renderer-indigo/src/client/resources/fabric.mod.json +++ b/fabric-renderer-indigo/src/client/resources/fabric.mod.json @@ -17,7 +17,7 @@ ], "depends": { "fabricloader": ">=0.18.4", - "minecraft": ">=1.21.5-beta.1", + "minecraft": ">=26.1-rc.2", "fabric-api-base": "*", "fabric-renderer-api-v1": "*" }, diff --git a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/mixin/AvatarRendererMixin.java b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/mixin/AvatarRendererMixin.java index 022f76cdab3..c2b809ccd7f 100644 --- a/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/mixin/AvatarRendererMixin.java +++ b/fabric-rendering-v1/src/testmodClient/java/net/fabricmc/fabric/test/rendering/client/mixin/AvatarRendererMixin.java @@ -23,7 +23,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import net.minecraft.client.entity.ClientAvatarEntity; -import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.renderer.block.BlockModelRenderState; import net.minecraft.client.renderer.block.BlockModelResolver; import net.minecraft.client.renderer.block.model.BlockDisplayContext; @@ -50,10 +49,6 @@ private void init(EntityRendererProvider.Context context, boolean slimSteve, Cal @Inject(method = "extractRenderState(Lnet/minecraft/world/entity/Avatar;Lnet/minecraft/client/renderer/entity/state/AvatarRenderState;F)V", at = @At("RETURN")) private void extractRenderState(AvatarlikeEntity entity, AvatarRenderState state, float partialTicks, CallbackInfo ci) { - if (!(entity instanceof LocalPlayer player)) { - return; - } - BlockModelRenderState blockRenderState = state.getData(RenderLayerTest.DIAMOND_BLOCK); if (blockRenderState == null) { diff --git a/settings.gradle b/settings.gradle index 5b58ec989c1..8e249715bc4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -49,14 +49,14 @@ 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-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'