diff --git a/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch b/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch index 28eac003aa..a23deb9c13 100644 --- a/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch @@ -109,7 +109,7 @@ + BLOCK_RENDER_TYPES.put(net.minecraftforge.registries.ForgeRegistries.BLOCKS.getDelegateOrThrow(block), layers); + } + -+ public static void setRenderLayer(Fluid fluid, RenderType type) { ++ public static synchronized void setRenderLayer(Fluid fluid, RenderType type) { + com.google.common.base.Preconditions.checkArgument(type.getChunkLayerId() >= 0, "The argument must be a valid chunk render type returned by RenderType#chunkBufferLayers()."); + checkClientLoading(); + FLUID_RENDER_TYPES.put(net.minecraftforge.registries.ForgeRegistries.FLUIDS.getDelegateOrThrow(fluid), type); diff --git a/patches/minecraft/net/minecraft/client/renderer/block/model/BlockModel.java.patch b/patches/minecraft/net/minecraft/client/renderer/block/model/BlockModel.java.patch index f32751039a..a6a89c93f4 100644 --- a/patches/minecraft/net/minecraft/client/renderer/block/model/BlockModel.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/block/model/BlockModel.java.patch @@ -49,7 +49,7 @@ for(BlockElement blockelement : this.m_111436_()) { for(BlockElementFace blockelementface : blockelement.f_111310_.values()) { Material material = this.m_111480_(blockelementface.f_111356_); -@@ -181,11 +_,17 @@ +@@ -181,11 +_,18 @@ return set1; } @@ -62,20 +62,12 @@ + return net.minecraftforge.client.model.geometry.UnbakedGeometryHelper.bake(this, p_111450_, p_111451_, p_111452_, p_111453_, p_111454_, p_111455_); + } + -+ @Deprecated //Forge: exposed for our callbacks only. Use the above function. ++ @Deprecated(forRemoval = true, since = "1.19.2") // TODO: We cannot remove it since it's vanilla code, but make it private in 1.20 + public BakedModel bakeVanilla(ModelBakery p_111450_, BlockModel p_111451_, Function p_111452_, ModelState p_111453_, ResourceLocation p_111454_, boolean p_111455_, net.minecraftforge.client.RenderTypeGroup renderTypes) { ++ if (true) return net.minecraftforge.client.model.geometry.UnbakedGeometryHelper.bakeVanilla(this, p_111450_, p_111451_, p_111452_, p_111453_, p_111454_); // Redirected, in case anyone actually uses this TextureAtlasSprite textureatlassprite = p_111452_.apply(this.m_111480_("particle")); if (this.m_111490_() == ModelBakery.f_119233_) { return new BuiltInModel(this.m_111491_(), this.m_111446_(p_111450_, p_111451_), textureatlassprite, this.m_111479_().m_111526_()); -@@ -204,7 +_,7 @@ - } - } - -- return simplebakedmodel$builder.m_119533_(); -+ return simplebakedmodel$builder.build(renderTypes); - } - } - @@ -268,7 +_,18 @@ ItemTransform itemtransform5 = this.m_111444_(ItemTransforms.TransformType.GUI); ItemTransform itemtransform6 = this.m_111444_(ItemTransforms.TransformType.GROUND); diff --git a/src/main/java/net/minecraftforge/client/model/CompositeModel.java b/src/main/java/net/minecraftforge/client/model/CompositeModel.java index 0e8ebed304..3415f7f72e 100644 --- a/src/main/java/net/minecraftforge/client/model/CompositeModel.java +++ b/src/main/java/net/minecraftforge/client/model/CompositeModel.java @@ -23,10 +23,12 @@ import net.minecraft.client.resources.model.Material; import net.minecraft.client.resources.model.ModelBakery; import net.minecraft.client.resources.model.ModelState; import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.RandomSource; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.client.ChunkRenderTypeSet; import net.minecraftforge.client.RenderTypeGroup; @@ -169,6 +171,15 @@ public class CompositeModel implements IUnbakedGeometry return ConcatenatedListView.of(quadLists); } + @Override + public @NotNull ModelData getModelData(@NotNull BlockAndTintGetter level, @NotNull BlockPos pos, @NotNull BlockState state, @NotNull ModelData modelData) + { + var builder = Data.builder(); + for (var entry : children.entrySet()) + builder.with(entry.getKey(), entry.getValue().getModelData(level, pos, state, Data.resolve(modelData, entry.getKey()))); + return modelData.derive().with(Data.PROPERTY, builder.build()).build(); + } + @Override public boolean useAmbientOcclusion() { diff --git a/src/main/java/net/minecraftforge/client/model/ElementsModel.java b/src/main/java/net/minecraftforge/client/model/ElementsModel.java index daa33f2634..c1fe70fbf7 100644 --- a/src/main/java/net/minecraftforge/client/model/ElementsModel.java +++ b/src/main/java/net/minecraftforge/client/model/ElementsModel.java @@ -62,9 +62,11 @@ public class ElementsModel extends SimpleUnbakedGeometry if (deprecatedLoader) LOGGER.warn("Model \"" + modelLocation + "\" is using the deprecated loader \"minecraft:elements\" instead of \"forge:elements\". This loader will be removed in 1.20."); - var rootTransform = context.getRootTransform(); - if (!rootTransform.isIdentity()) - modelState = new SimpleModelState(modelState.getRotation().compose(rootTransform), modelState.isUvLocked()); + // If there is a root transform, undo the ModelState transform, apply it, then re-apply the ModelState transform. + // This is necessary because of things like UV locking, which should only respond to the ModelState, and as such + // that is the only transform that should be applied during face bake. + var postTransform = context.getRootTransform().isIdentity() ? QuadTransformers.empty() : + QuadTransformers.applying(modelState.getRotation().compose(context.getRootTransform()).compose(modelState.getRotation().inverse())); for (BlockElement element : elements) { @@ -73,6 +75,7 @@ public class ElementsModel extends SimpleUnbakedGeometry var face = element.faces.get(direction); var sprite = spriteGetter.apply(context.getMaterial(face.texture)); var quad = BlockModel.bakeFace(element, face, sprite, direction, modelState, modelLocation); + postTransform.processInPlace(quad); if (face.cullForDirection == null) modelBuilder.addUnculledFace(quad); diff --git a/src/main/java/net/minecraftforge/client/model/QuadTransformers.java b/src/main/java/net/minecraftforge/client/model/QuadTransformers.java index 406df8f454..b413738b58 100644 --- a/src/main/java/net/minecraftforge/client/model/QuadTransformers.java +++ b/src/main/java/net/minecraftforge/client/model/QuadTransformers.java @@ -64,7 +64,7 @@ public final class QuadTransformers { { int offset = i * IQuadTransformer.STRIDE + IQuadTransformer.NORMAL; int normalIn = vertices[offset]; - if ((normalIn >> 8) != 0) + if ((normalIn & 0x00FFFFFF) != 0) // The ignored byte is padding and may be filled with user data { float x = ((byte) (normalIn & 0xFF)) / 127.0f; float y = ((byte) ((normalIn >> 8) & 0xFF)) / 127.0f; @@ -72,12 +72,11 @@ public final class QuadTransformers { Vector3f pos = new Vector3f(x, y, z); transform.transformNormal(pos); - pos.normalize(); - vertices[offset] = (((byte) (x * 127.0f)) & 0xFF) | - ((((byte) (y * 127.0f)) & 0xFF) << 8) | - ((((byte) (z * 127.0f)) & 0xFF) << 16) | - (normalIn & 0xFF000000); + vertices[offset] = (((byte) (pos.x() * 127.0f)) & 0xFF) | + ((((byte) (pos.y() * 127.0f)) & 0xFF) << 8) | + ((((byte) (pos.z() * 127.0f)) & 0xFF) << 16) | + (normalIn & 0xFF000000); // Restore padding, just in case } } }; diff --git a/src/main/java/net/minecraftforge/client/model/geometry/UnbakedGeometryHelper.java b/src/main/java/net/minecraftforge/client/model/geometry/UnbakedGeometryHelper.java index e193861045..8a2ebab11e 100644 --- a/src/main/java/net/minecraftforge/client/model/geometry/UnbakedGeometryHelper.java +++ b/src/main/java/net/minecraftforge/client/model/geometry/UnbakedGeometryHelper.java @@ -19,12 +19,13 @@ import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.BuiltInModel; import net.minecraft.client.resources.model.Material; import net.minecraft.client.resources.model.ModelBakery; import net.minecraft.client.resources.model.ModelState; import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.RenderTypeGroup; +import net.minecraftforge.client.model.ElementsModel; import net.minecraftforge.client.model.IModelBuilder; import net.minecraftforge.client.model.SimpleModelState; import org.jetbrains.annotations.ApiStatus; @@ -98,17 +99,30 @@ public class UnbakedGeometryHelper if (customModel != null) return customModel.bake(blockModel.customData, modelBakery, spriteGetter, modelState, blockModel.getOverrides(modelBakery, owner, spriteGetter), modelLocation); - Transformation rootTransform = blockModel.customData.getRootTransform(); - if (!rootTransform.isIdentity()) - modelState = new SimpleModelState(modelState.getRotation().compose(rootTransform), modelState.isUvLocked()); - // Handle vanilla item models here, since vanilla has a shortcut for them if (blockModel.getRootModel() == ModelBakery.GENERATION_MARKER) return ITEM_MODEL_GENERATOR.generateBlockModel(spriteGetter, blockModel).bake(modelBakery, blockModel, spriteGetter, modelState, modelLocation, guiLight3d); - var renderTypeHint = blockModel.customData.getRenderTypeHint(); - var renderTypes = renderTypeHint != null ? blockModel.customData.getRenderType(renderTypeHint) : RenderTypeGroup.EMPTY; - return blockModel.bakeVanilla(modelBakery, owner, spriteGetter, modelState, modelLocation, guiLight3d, renderTypes); + return bakeVanilla(blockModel, modelBakery, owner, spriteGetter, modelState, modelLocation); + } + + /** + * Helper for baking vanilla {@link BlockModel} instances. + * + * @deprecated Merge into the method above in 1.20 once the call from {@link BlockModel} is gone. + */ + @ApiStatus.Internal + @Deprecated(forRemoval = true, since = "1.19.2") + public static BakedModel bakeVanilla(BlockModel blockModel, ModelBakery modelBakery, BlockModel owner, Function spriteGetter, ModelState modelState, ResourceLocation modelLocation) + { + if (blockModel.getRootModel() == ModelBakery.BLOCK_ENTITY_MARKER) + { + var particleSprite = spriteGetter.apply(blockModel.getMaterial("particle")); + return new BuiltInModel(blockModel.getTransforms(), blockModel.getOverrides(modelBakery, owner, spriteGetter), particleSprite, blockModel.getGuiLight().lightLikeBlock()); + } + + var elementsModel = new ElementsModel(blockModel.getElements()); + return elementsModel.bake(blockModel.customData, modelBakery, spriteGetter, modelState, blockModel.getOverrides(modelBakery, owner, spriteGetter), modelLocation); } /** diff --git a/src/main/java/net/minecraftforge/client/model/obj/ObjModel.java b/src/main/java/net/minecraftforge/client/model/obj/ObjModel.java index 034b9f12a0..96bfcfb3d3 100644 --- a/src/main/java/net/minecraftforge/client/model/obj/ObjModel.java +++ b/src/main/java/net/minecraftforge/client/model/obj/ObjModel.java @@ -68,7 +68,7 @@ public class ObjModel extends SimpleUnbakedGeometry new Vec2(1, 0), }; - private final Map parts = Maps.newHashMap(); + private final Map parts = Maps.newLinkedHashMap(); private final Set rootComponentNames = Collections.unmodifiableSet(parts.keySet()); private Set allComponentNames; @@ -402,8 +402,7 @@ public class ObjModel extends SimpleUnbakedGeometry faceNormal = abs; } - var quad = new BakedQuad[1]; - var quadBaker = new QuadBakingVertexConsumer(q -> quad[0] = q); + var quadBaker = new QuadBakingVertexConsumer.Buffered(); quadBaker.setSprite(texture); quadBaker.setTintIndex(tintIndex); @@ -516,7 +515,7 @@ public class ObjModel extends SimpleUnbakedGeometry } } - return Pair.of(quad[0], cull); + return Pair.of(quadBaker.getQuad(), cull); } public CompositeRenderable bakeRenderable(IGeometryBakingContext configuration) @@ -582,7 +581,7 @@ public class ObjModel extends SimpleUnbakedGeometry public class ModelGroup extends ModelObject { - final Map parts = Maps.newHashMap(); + final Map parts = Maps.newLinkedHashMap(); ModelGroup(String name) { @@ -652,9 +651,11 @@ public class ObjModel extends SimpleUnbakedGeometry int tintIndex = mat.diffuseTintIndex; Vector4f colorTint = mat.diffuseColor; + var rootTransform = owner.getRootTransform(); + var transform = rootTransform.isIdentity() ? modelTransform.getRotation() : modelTransform.getRotation().compose(rootTransform); for (int[][] face : faces) { - Pair quad = makeQuad(face, tintIndex, colorTint, mat.ambientColor, texture, modelTransform.getRotation()); + Pair quad = makeQuad(face, tintIndex, colorTint, mat.ambientColor, texture, transform); if (quad.getRight() == null) modelBuilder.addUnculledFace(quad.getLeft()); else diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/QuadBakingVertexConsumer.java b/src/main/java/net/minecraftforge/client/model/pipeline/QuadBakingVertexConsumer.java index cb6018f761..7d5d433655 100644 --- a/src/main/java/net/minecraftforge/client/model/pipeline/QuadBakingVertexConsumer.java +++ b/src/main/java/net/minecraftforge/client/model/pipeline/QuadBakingVertexConsumer.java @@ -5,6 +5,7 @@ package net.minecraftforge.client.model.pipeline; +import com.google.common.base.Preconditions; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexFormatElement; @@ -37,7 +38,7 @@ public class QuadBakingVertexConsumer implements VertexConsumer private final Consumer quadConsumer; - private int vertexIndex = 0; + int vertexIndex = 0; private int[] quadData = new int[QUAD_DATA_SIZE]; private int tintIndex; @@ -167,4 +168,27 @@ public class QuadBakingVertexConsumer implements VertexConsumer { this.hasAmbientOcclusion = hasAmbientOcclusion; } + + public static class Buffered extends QuadBakingVertexConsumer + { + private final BakedQuad[] output; + + public Buffered() + { + this(new BakedQuad[1]); + } + + private Buffered(BakedQuad[] output) + { + super(q -> output[0] = q); + this.output = output; + } + + public BakedQuad getQuad() + { + var quad = Preconditions.checkNotNull(output[0], "No quad has been emitted. Vertices in buffer: " + vertexIndex); + output[0] = null; + return quad; + } + } } diff --git a/src/test/java/net/minecraftforge/debug/client/model/NewModelLoaderTest.java b/src/test/java/net/minecraftforge/debug/client/model/NewModelLoaderTest.java index dfec3b5c81..f911938756 100644 --- a/src/test/java/net/minecraftforge/debug/client/model/NewModelLoaderTest.java +++ b/src/test/java/net/minecraftforge/debug/client/model/NewModelLoaderTest.java @@ -156,8 +156,7 @@ public class NewModelLoaderTest { TextureAtlasSprite texture = spriteGetter.apply(owner.getMaterial("particle")); - var quad = new BakedQuad[1]; - var quadBaker = new QuadBakingVertexConsumer(q -> quad[0] = q); + var quadBaker = new QuadBakingVertexConsumer.Buffered(); quadBaker.setDirection(Direction.UP); quadBaker.setSprite(texture); @@ -167,7 +166,7 @@ public class NewModelLoaderTest quadBaker.vertex(1, 0, 0.5f).color(255, 255, 255, 255).uv(texture.getU(16), texture.getV(16)).uv2(0).normal(0, 0, 0).endVertex(); quadBaker.vertex(1, 1, 0.5f).color(255, 255, 255, 255).uv(texture.getU(16), texture.getV(0)).uv2(0).normal(0, 0, 0).endVertex(); - modelBuilder.addUnculledFace(quad[0]); + modelBuilder.addUnculledFace(quadBaker.getQuad()); } @Override