From 30f255d76c4c2e915414a24e6d8aed42f429817e Mon Sep 17 00:00:00 2001 From: Kovak Date: Mon, 17 Jul 2023 18:10:12 -0700 Subject: [PATCH] Fix breaking overlay flickering on campfires by using vanilla method to calculate block normals. (#9664) --- .../block/model/FaceBakery.java.patch | 2 +- .../client/ForgeHooksClient.java | 29 ++++++++++++------- .../client/model/ForgeFaceData.java | 12 ++++++-- .../client/model/generators/ModelBuilder.java | 28 ++++++++++++++++-- .../loaders/ItemLayerModelBuilder.java | 4 +-- 5 files changed, 57 insertions(+), 18 deletions(-) diff --git a/patches/minecraft/net/minecraft/client/renderer/block/model/FaceBakery.java.patch b/patches/minecraft/net/minecraft/client/renderer/block/model/FaceBakery.java.patch index a5e2d11c9b..0a7d0e625d 100644 --- a/patches/minecraft/net/minecraft/client/renderer/block/model/FaceBakery.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/block/model/FaceBakery.java.patch @@ -5,7 +5,7 @@ } - return new BakedQuad(aint, p_111603_.f_111355_, direction, p_111604_, p_111608_); -+ net.minecraftforge.client.ForgeHooksClient.fillNormal(aint, direction); ++ net.minecraftforge.client.ForgeHooksClient.fillNormal(aint, direction, p_111603_.getFaceData().calculateNormals()); + var data = p_111603_.getFaceData(); + var quad = new BakedQuad(aint, p_111603_.f_111355_, direction, p_111604_, p_111608_, data.ambientOcclusion()); + if (!net.minecraftforge.client.model.ForgeFaceData.DEFAULT.equals(data)) { diff --git a/src/main/java/net/minecraftforge/client/ForgeHooksClient.java b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java index 4b6dc99390..a24f8f64e7 100644 --- a/src/main/java/net/minecraftforge/client/ForgeHooksClient.java +++ b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java @@ -496,21 +496,30 @@ public class ForgeHooksClient return new Material(TextureAtlas.LOCATION_BLOCKS, loc); } + public static void fillNormal(int[] faceData, Direction facing) + { + fillNormal(faceData, facing, false); + } + /** * internal, relies on fixed format of FaceBakery */ // TODO Do we need this? - public static void fillNormal(int[] faceData, Direction facing) + public static void fillNormal(int[] faceData, Direction facing, boolean calculateNormals) { - Vector3f v1 = getVertexPos(faceData, 3); - Vector3f t1 = getVertexPos(faceData, 1); - Vector3f v2 = getVertexPos(faceData, 2); - Vector3f t2 = getVertexPos(faceData, 0); - v1.sub(t1); - v2.sub(t2); - v2.cross(v1); - v2.normalize(); - + Vector3f v2; + if (calculateNormals) { + Vector3f v1 = getVertexPos(faceData, 3); + Vector3f t1 = getVertexPos(faceData, 1); + v2 = getVertexPos(faceData, 2); + Vector3f t2 = getVertexPos(faceData, 0); + v1.sub(t1); + v2.sub(t2); + v2.cross(v1); + v2.normalize(); + } else { + v2 = new Vector3f(facing.getNormal().getX(), facing.getNormal().getY(), facing.getNormal().getZ()); + } int x = ((byte) Math.round(v2.x() * 127)) & 0xFF; int y = ((byte) Math.round(v2.y() * 127)) & 0xFF; int z = ((byte) Math.round(v2.z() * 127)) & 0xFF; diff --git a/src/main/java/net/minecraftforge/client/model/ForgeFaceData.java b/src/main/java/net/minecraftforge/client/model/ForgeFaceData.java index 1f00870a7e..c41005202f 100644 --- a/src/main/java/net/minecraftforge/client/model/ForgeFaceData.java +++ b/src/main/java/net/minecraftforge/client/model/ForgeFaceData.java @@ -28,11 +28,16 @@ import net.minecraft.util.ExtraCodecs; * @param blockLight Block Light for this face from 0-15 (inclusive) * @param skyLight Sky Light for this face from 0-15 (inclusive) * @param ambientOcclusion If this face has AO + * @param calculateNormals If we should manually calculate the normals for this block or inherit facing normals like vanilla */ -public record ForgeFaceData(int color, int blockLight, int skyLight, boolean ambientOcclusion) +public record ForgeFaceData(int color, int blockLight, int skyLight, boolean ambientOcclusion, boolean calculateNormals) { + public ForgeFaceData(int color, int blockLight, int skyLight, boolean ambientOcclusion) + { + this(color, blockLight, skyLight, ambientOcclusion, false); + } - public static final ForgeFaceData DEFAULT = new ForgeFaceData(0xFFFFFFFF, 0, 0, true); + public static final ForgeFaceData DEFAULT = new ForgeFaceData(0xFFFFFFFF, 0, 0, true, false); public static final Codec COLOR = new ExtraCodecs.EitherCodec<>(Codec.INT, Codec.STRING).xmap( either -> either.map(Function.identity(), str -> (int) Long.parseLong(str, 16)), @@ -42,7 +47,8 @@ public record ForgeFaceData(int color, int blockLight, int skyLight, boolean amb COLOR.optionalFieldOf("color", 0xFFFFFFFF).forGetter(ForgeFaceData::color), Codec.intRange(0, 15).optionalFieldOf("block_light", 0).forGetter(ForgeFaceData::blockLight), Codec.intRange(0, 15).optionalFieldOf("sky_light", 0).forGetter(ForgeFaceData::skyLight), - Codec.BOOL.optionalFieldOf("ambient_occlusion", true).forGetter(ForgeFaceData::ambientOcclusion)) + Codec.BOOL.optionalFieldOf("ambient_occlusion", true).forGetter(ForgeFaceData::ambientOcclusion), + Codec.BOOL.optionalFieldOf("calculate_normals", false).forGetter(ForgeFaceData::calculateNormals)) .apply(builder, ForgeFaceData::new)); /** diff --git a/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java index ef8bedb3c8..e159e4501d 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java +++ b/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java @@ -388,6 +388,7 @@ public class ModelBuilder> extends ModelFile { private int color = 0xFFFFFFFF; private int blockLight = 0, skyLight = 0; private boolean hasAmbientOcclusion = true; + private boolean calculateNormals = false; private void validateCoordinate(float coord, char name) { Preconditions.checkArgument(!(coord < -16.0F) && !(coord > 32.0F), "Position " + name + " out of range, must be within [-16, 32]. Found: %d", coord); @@ -556,6 +557,17 @@ public class ModelBuilder> extends ModelFile { return this; } + /** + * Sets whether we should calculate actual normals for the faces of this model or inherit them from facing the + * way vanilla does + * @param calc whether to calculate normals + * @return this builder + */ + public ElementBuilder calculateNormals(boolean calc) { + this.calculateNormals = calc; + return this; + } + private BiConsumer addTexture(String texture) { return ($, f) -> f.texture(texture); } @@ -563,7 +575,7 @@ public class ModelBuilder> extends ModelFile { BlockElement build() { Map faces = this.faces.entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().build(), (k1, k2) -> { throw new IllegalArgumentException(); }, LinkedHashMap::new)); - return new BlockElement(from, to, faces, rotation == null ? null : rotation.build(), shade, new ForgeFaceData(this.color, this.blockLight, this.skyLight, this.hasAmbientOcclusion)); + return new BlockElement(from, to, faces, rotation == null ? null : rotation.build(), shade, new ForgeFaceData(this.color, this.blockLight, this.skyLight, this.hasAmbientOcclusion, this.calculateNormals)); } public T end() { return self(); } @@ -578,6 +590,7 @@ public class ModelBuilder> extends ModelFile { private int color = 0xFFFFFFFF; private int blockLight = 0, skyLight = 0; private boolean hasAmbientOcclusion = true; + private boolean calculateNormals = false; FaceBuilder(Direction dir) { // param unused for functional match @@ -660,11 +673,22 @@ public class ModelBuilder> extends ModelFile { return this; } + /** + * Sets whether we should calculate actual normals for this face or inherit them from facing the + * way vanilla does + * @param calc whether to calculate normals + * @return this builder + */ + public FaceBuilder calculateNormals(boolean calc) { + this.calculateNormals = calc; + return this; + } + BlockElementFace build() { if (this.texture == null) { throw new IllegalStateException("A model face must have a texture"); } - return new BlockElementFace(cullface, tintindex, texture, new BlockFaceUV(uvs, rotation.rotation), new ForgeFaceData(this.color, this.blockLight, this.skyLight, this.hasAmbientOcclusion)); + return new BlockElementFace(cullface, tintindex, texture, new BlockFaceUV(uvs, rotation.rotation), new ForgeFaceData(this.color, this.blockLight, this.skyLight, this.hasAmbientOcclusion, this.calculateNormals)); } public ElementBuilder end() { return ElementBuilder.this; } diff --git a/src/main/java/net/minecraftforge/client/model/generators/loaders/ItemLayerModelBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/loaders/ItemLayerModelBuilder.java index b0d8fe3a11..2ace668347 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/loaders/ItemLayerModelBuilder.java +++ b/src/main/java/net/minecraftforge/client/model/generators/loaders/ItemLayerModelBuilder.java @@ -60,7 +60,7 @@ public class ItemLayerModelBuilder> extends CustomLoad { faceData.compute(i, (key, value) -> { ForgeFaceData fallback = value == null ? ForgeFaceData.DEFAULT : value; - return new ForgeFaceData(fallback.color(), blockLight, skyLight, fallback.ambientOcclusion()); + return new ForgeFaceData(fallback.color(), blockLight, skyLight, fallback.ambientOcclusion(), fallback.calculateNormals()); }); } return this; @@ -85,7 +85,7 @@ public class ItemLayerModelBuilder> extends CustomLoad { faceData.compute(i, (key, value) -> { ForgeFaceData fallback = value == null ? ForgeFaceData.DEFAULT : value; - return new ForgeFaceData(color, fallback.blockLight(), fallback.skyLight(), fallback.ambientOcclusion()); + return new ForgeFaceData(color, fallback.blockLight(), fallback.skyLight(), fallback.ambientOcclusion(), fallback.calculateNormals()); }); } return this;