From 2b8f781c7f3a30fe2598486eeadb1cbe158b3a80 Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Thu, 20 Jul 2023 09:33:43 -0600 Subject: [PATCH 1/6] Improve flat shade - Use AO mode to make flat shade calculation consistent with shade applied by smooth lighting - Use face normal to calculate shade if necessary - Use normal shade even if no custom normals are set --- .../indigo/renderer/mesh/QuadViewImpl.java | 5 ++ .../render/AbstractBlockRenderContext.java | 60 ++++++++++++++----- 2 files changed, 50 insertions(+), 15 deletions(-) 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 bff60b303c..84fc20082b 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 @@ -173,6 +173,11 @@ public boolean hasVertexNormals() { return normalFlags() != 0; } + /** True if all vertex normals have been set. */ + public boolean hasAllVertexNormals() { + return (normalFlags() & 0b1111) == 0b1111; + } + protected final int normalIndex(int vertexIndex) { return baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_NORMAL; } diff --git a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/AbstractBlockRenderContext.java b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/AbstractBlockRenderContext.java index df72f3bf7e..610549e164 100644 --- a/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/AbstractBlockRenderContext.java +++ b/fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/render/AbstractBlockRenderContext.java @@ -22,6 +22,7 @@ import java.util.List; import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; import net.minecraft.block.BlockState; import net.minecraft.client.render.LightmapTextureManager; @@ -37,8 +38,10 @@ import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper; import net.fabricmc.fabric.api.util.TriState; +import net.fabricmc.fabric.impl.client.indigo.Indigo; import net.fabricmc.fabric.impl.client.indigo.renderer.IndigoRenderer; import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.AoCalculator; +import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.AoConfig; import net.fabricmc.fabric.impl.client.indigo.renderer.helper.ColorHelper; import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.EncodingFormat; import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl; @@ -131,7 +134,7 @@ private void shadeQuad(MutableQuadViewImpl quad, boolean isVanilla, boolean ao, } } } else { - shadeFlatQuad(quad); + shadeFlatQuad(quad, isVanilla); if (emissive) { for (int i = 0; i < 4; i++) { @@ -151,30 +154,57 @@ private void shadeQuad(MutableQuadViewImpl quad, boolean isVanilla, boolean ao, * 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) { - if (quad.hasVertexNormals()) { - // Quads that have vertex normals need to be shaded using interpolation - vanilla can't - // handle them. Generally only applies to modded models. - final float faceShade = blockInfo.blockView.getBrightness(quad.lightFace(), quad.hasShade()); + private void shadeFlatQuad(MutableQuadViewImpl quad, boolean isVanilla) { + final boolean hasShade = quad.hasShade(); - for (int i = 0; i < 4; i++) { - quad.color(i, ColorHelper.multiplyRGB(quad.color(i), vertexShade(quad, i, faceShade))); + // Check the AO mode to match how shade is applied during smooth lighting + if ((Indigo.AMBIENT_OCCLUSION_MODE == AoConfig.HYBRID && !isVanilla) || 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, ColorHelper.multiplyRGB(quad.color(i), shade)); + } + } else { + final float faceShade; + + if ((quad.geometryFlags() & AXIS_ALIGNED_FLAG) != 0) { + faceShade = blockInfo.blockView.getBrightness(quad.lightFace(), hasShade); + } else { + Vector3f 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, ColorHelper.multiplyRGB(quad.color(i), shade)); + } + } else { + if (faceShade != 1.0f) { + for (int i = 0; i < 4; i++) { + quad.color(i, ColorHelper.multiplyRGB(quad.color(i), faceShade)); + } + } + } } } else { - final float diffuseShade = blockInfo.blockView.getBrightness(quad.lightFace(), quad.hasShade()); + final float faceShade = blockInfo.blockView.getBrightness(quad.lightFace(), hasShade); - if (diffuseShade != 1.0f) { + if (faceShade != 1.0f) { for (int i = 0; i < 4; i++) { - quad.color(i, ColorHelper.multiplyRGB(quad.color(i), diffuseShade)); + quad.color(i, ColorHelper.multiplyRGB(quad.color(i), faceShade)); } } } } - private float vertexShade(MutableQuadViewImpl quad, int vertexIndex, float faceShade) { - return quad.hasNormal(vertexIndex) ? normalShade(quad.normalX(vertexIndex), quad.normalY(vertexIndex), quad.normalZ(vertexIndex), quad.hasShade()) : 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 From 42ed8a23b1e2744074fda16b0e4be644de45b2c9 Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Thu, 20 Jul 2023 09:36:13 -0600 Subject: [PATCH 2/6] Improve FRAPI test mod - Add octagonal column to test irregular face lighting - Use obsidian sprite instead of missing sprite for frame mesh - Simplify and organize registration - Inline `simple` package --- .../renderer/{simple => }/FrameBlock.java | 13 +- .../{simple => }/FrameBlockEntity.java | 6 +- .../fabric/test/renderer/Registration.java | 49 ++++ .../fabric/test/renderer/RendererTest.java | 53 +++++ .../fabric/test/renderer/package-info.java | 26 --- .../test/renderer/simple/RendererTest.java | 68 ------ .../src/testmod/resources/fabric.mod.json | 5 +- .../{simple => }/client/FrameBakedModel.java | 88 ++++---- .../renderer/client/FrameUnbakedModel.java | 118 ++++++++++ .../renderer/client/ModelResolverImpl.java | 50 +++++ .../client/OctagonalColumnUnbakedModel.java | 210 ++++++++++++++++++ .../{simple => }/client/PillarBakedModel.java | 48 ++-- .../client/PillarUnbakedModel.java | 7 +- .../client/RendererClientTest.java | 40 +--- .../renderer/client/SingleMeshBakedModel.java | 88 ++++++++ .../simple/client/FrameUnbakedModel.java | 120 ---------- .../blockstates/octagonal_column.json | 5 + .../blockstates/pillar.json | 5 + 18 files changed, 660 insertions(+), 339 deletions(-) rename fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/{simple => }/FrameBlock.java (89%) rename fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/{simple => }/FrameBlockEntity.java (92%) create mode 100644 fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java create mode 100644 fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/RendererTest.java delete mode 100644 fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/package-info.java delete mode 100644 fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/RendererTest.java rename fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/{simple => }/client/FrameBakedModel.java (96%) create mode 100644 fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameUnbakedModel.java create mode 100644 fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/ModelResolverImpl.java create mode 100644 fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OctagonalColumnUnbakedModel.java rename fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/{simple => }/client/PillarBakedModel.java (73%) rename fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/{simple => }/client/PillarUnbakedModel.java (92%) rename fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/{simple => }/client/RendererClientTest.java (55%) create mode 100644 fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/SingleMeshBakedModel.java delete mode 100644 fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/simple/client/FrameUnbakedModel.java create mode 100644 fabric-renderer-api-v1/src/testmodClient/resources/assets/fabric-renderer-api-v1-testmod/blockstates/octagonal_column.json create mode 100644 fabric-renderer-api-v1/src/testmodClient/resources/assets/fabric-renderer-api-v1-testmod/blockstates/pillar.json diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/FrameBlock.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java similarity index 89% rename from fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/FrameBlock.java rename to fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java index 74e5dfafe4..34cccae9e5 100644 --- a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/FrameBlock.java +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlock.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.test.renderer.simple; +package net.fabricmc.fabric.test.renderer; import org.jetbrains.annotations.Nullable; @@ -27,7 +27,6 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; -import net.minecraft.util.Identifier; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; @@ -35,16 +34,12 @@ import net.minecraft.world.World; import net.fabricmc.fabric.api.block.v1.FabricBlock; -import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView; // Need to implement FabricBlock manually because this is a testmod for another Fabric module, otherwise it would be injected. -public final class FrameBlock extends Block implements BlockEntityProvider, FabricBlock { - public final Identifier id; - - public FrameBlock(Identifier id) { - super(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque()); - this.id = id; +public class FrameBlock extends Block implements BlockEntityProvider, FabricBlock { + public FrameBlock(Settings settings) { + super(settings); } @Override diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/FrameBlockEntity.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlockEntity.java similarity index 92% rename from fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/FrameBlockEntity.java rename to fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlockEntity.java index 5ed12957e8..a90ae82369 100644 --- a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/FrameBlockEntity.java +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/FrameBlockEntity.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.test.renderer.simple; +package net.fabricmc.fabric.test.renderer; import org.jetbrains.annotations.Nullable; @@ -31,12 +31,12 @@ import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachmentBlockEntity; -public final class FrameBlockEntity extends BlockEntity implements RenderAttachmentBlockEntity { +public class FrameBlockEntity extends BlockEntity implements RenderAttachmentBlockEntity { @Nullable private Block block = null; public FrameBlockEntity(BlockPos blockPos, BlockState blockState) { - super(RendererTest.FRAME_BLOCK_ENTITY, blockPos, blockState); + super(Registration.FRAME_BLOCK_ENTITY_TYPE, blockPos, blockState); } @Override diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java new file mode 100644 index 0000000000..229b83058d --- /dev/null +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java @@ -0,0 +1,49 @@ +package net.fabricmc.fabric.test.renderer; + +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.item.BlockItem; +import net.minecraft.item.Item; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; + +import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; +import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; + +public final class Registration { + public static final FrameBlock FRAME_BLOCK = register("frame", new FrameBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque())); + public static final FrameBlock FRAME_MULTIPART_BLOCK = register("frame_multipart", new FrameBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque())); + public static final FrameBlock FRAME_VARIANT_BLOCK = register("frame_variant", new FrameBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque())); + public static final Block PILLAR_BLOCK = register("pillar", new Block(FabricBlockSettings.create())); + public static final Block OCTAGONAL_COLUMN_BLOCK = register("octagonal_column", new Block(FabricBlockSettings.create().nonOpaque())); + + public static final FrameBlock[] FRAME_BLOCKS = new FrameBlock[] { + FRAME_BLOCK, + FRAME_MULTIPART_BLOCK, + FRAME_VARIANT_BLOCK, + }; + + public static final Item FRAME_ITEM = register("frame", new BlockItem(FRAME_BLOCK, new Item.Settings())); + public static final Item FRAME_MULTIPART_ITEM = register("frame_multipart", new BlockItem(FRAME_MULTIPART_BLOCK, new Item.Settings())); + public static final Item FRAME_VARIANT_ITEM = register("frame_variant", new BlockItem(FRAME_VARIANT_BLOCK, new Item.Settings())); + public static final Item PILLAR_ITEM = register("pillar", new BlockItem(PILLAR_BLOCK, new Item.Settings())); + public static final Item OCTAGONAL_COLUMN_ITEM = register("octagonal_column", new BlockItem(OCTAGONAL_COLUMN_BLOCK, new Item.Settings())); + + public static final BlockEntityType FRAME_BLOCK_ENTITY_TYPE = register("frame", FabricBlockEntityTypeBuilder.create(FrameBlockEntity::new, FRAME_BLOCKS).build(null)); + + private static T register(String path, T block) { + return Registry.register(Registries.BLOCK, RendererTest.id(path), block); + } + + private static T register(String path, T item) { + return Registry.register(Registries.ITEM, RendererTest.id(path), item); + } + + private static > T register(String path, T blockEntityType) { + return Registry.register(Registries.BLOCK_ENTITY_TYPE, RendererTest.id(path), blockEntityType); + } + + public static void init() { + } +} diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/RendererTest.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/RendererTest.java new file mode 100644 index 0000000000..fc26a233a7 --- /dev/null +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/RendererTest.java @@ -0,0 +1,53 @@ +/* + * 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.test.renderer; + +import net.minecraft.util.Identifier; + +import net.fabricmc.api.ModInitializer; + + +/** + * The testmod for the Fabric Renderer API. These tests are used to validate that + * Indigo's implementation is correct, but they may also be useful for other + * implementations of the Fabric Renderer API. + * + *

Tests + * + *
    + *
  • Frame blocks displays another block inside, scaled down and made translucent. + * Blocks that provide a block entity cannot be placed inside frames. This also tests + * that mesh builders and meshes work properly. + * + *
  • Pillars connect vertically with each other by changing textures. They also + * connect vertically to frame blocks containing a pillar, and vice versa. + * + *
  • Octagonal columns have irregular faces to test enhanced AO and normal shade. The + * octagonal item column has glint force enabled on all faces except the top and bottom + * faces. This also tests that mesh builders and meshes work properly. + *
+ */ +public final class RendererTest implements ModInitializer { + @Override + public void onInitialize() { + Registration.init(); + } + + public static Identifier id(String path) { + return new Identifier("fabric-renderer-api-v1-testmod", path); + } +} diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/package-info.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/package-info.java deleted file mode 100644 index 0af08e4ffb..0000000000 --- a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/package-info.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. - */ - -/** - * The testmod for the Fabric Renderer API. - * Right now there is only one test here, but more tests may come to exist in the future. - * These tests are used to validate Indigo's implementation is correct, but these tests may also be useful for other implementations of the Fabric Renderer API. - * - *

Right now there is a simple test in the {@code simple} package which validates that simple meshes and quad emitters function. - * Future tests may look into testing things such as render materials or creating more advanced models. - */ - -package net.fabricmc.fabric.test.renderer; diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/RendererTest.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/RendererTest.java deleted file mode 100644 index e7e9e85845..0000000000 --- a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/simple/RendererTest.java +++ /dev/null @@ -1,68 +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.test.renderer.simple; - -import net.minecraft.block.Block; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.item.BlockItem; -import net.minecraft.item.Item; -import net.minecraft.registry.Registries; -import net.minecraft.registry.Registry; -import net.minecraft.util.Identifier; - -import net.fabricmc.api.ModInitializer; -import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; -import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; - -/** - * A simple testmod that renders a simple block rendered using the fabric renderer api. - * The block that is rendered is a simple frame that another block is rendered in. - * Blocks that provide a block entity cannot be placed inside the frame. - * - *

There are no fancy shaders or glow that is provided by this renderer test. - */ -public final class RendererTest implements ModInitializer { - public static final FrameBlock[] FRAMES = new FrameBlock[]{ - new FrameBlock(id("frame")), - new FrameBlock(id("frame_multipart")), - new FrameBlock(id("frame_weighted")), - }; - public static final BlockEntityType FRAME_BLOCK_ENTITY = FabricBlockEntityTypeBuilder.create(FrameBlockEntity::new, FRAMES).build(null); - - public static final Identifier PILLAR_ID = id("pillar"); - public static final Block PILLAR = new Block(FabricBlockSettings.create()); - - @Override - public void onInitialize() { - for (FrameBlock frameBlock : FRAMES) { - Registry.register(Registries.BLOCK, frameBlock.id, frameBlock); - Registry.register(Registries.ITEM, frameBlock.id, new BlockItem(frameBlock, new Item.Settings())); - } - - // To anyone testing this: pillars are supposed to connect vertically with each other. - // Additionally, they should also connect vertically to frame blocks containing a pillar. - // (The frame block will not change, but adjacent pillars should adjust their textures). - Registry.register(Registries.BLOCK, PILLAR_ID, PILLAR); - Registry.register(Registries.ITEM, PILLAR_ID, new BlockItem(PILLAR, new Item.Settings())); - - Registry.register(Registries.BLOCK_ENTITY_TYPE, id("frame"), FRAME_BLOCK_ENTITY); - } - - public static Identifier id(String path) { - return new Identifier("fabric-renderer-api-v1-testmod", path); - } -} diff --git a/fabric-renderer-api-v1/src/testmod/resources/fabric.mod.json b/fabric-renderer-api-v1/src/testmod/resources/fabric.mod.json index 1fd965e719..95124366a1 100644 --- a/fabric-renderer-api-v1/src/testmod/resources/fabric.mod.json +++ b/fabric-renderer-api-v1/src/testmod/resources/fabric.mod.json @@ -7,14 +7,15 @@ "license": "Apache-2.0", "depends": { "fabric-renderer-api-v1":"*", + "fabric-model-loading-api-v1":"*", "fabric-resource-loader-v0": "*" }, "entrypoints": { "main": [ - "net.fabricmc.fabric.test.renderer.simple.RendererTest" + "net.fabricmc.fabric.test.renderer.RendererTest" ], "client": [ - "net.fabricmc.fabric.test.renderer.simple.client.RendererClientTest" + "net.fabricmc.fabric.test.renderer.client.RendererClientTest" ] } } diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/simple/client/FrameBakedModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameBakedModel.java similarity index 96% rename from fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/simple/client/FrameBakedModel.java rename to fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameBakedModel.java index 388361a9d9..59a9210374 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/simple/client/FrameBakedModel.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameBakedModel.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.test.renderer.simple.client; +package net.fabricmc.fabric.test.renderer.client; import java.util.Collections; import java.util.List; @@ -46,13 +46,13 @@ import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView; -final class FrameBakedModel implements BakedModel { +public class FrameBakedModel implements BakedModel { private final Mesh frameMesh; private final Sprite frameSprite; private final RenderMaterial translucentMaterial; private final RenderMaterial translucentEmissiveMaterial; - FrameBakedModel(Mesh frameMesh, Sprite frameSprite) { + public FrameBakedModel(Mesh frameMesh, Sprite frameSprite) { this.frameMesh = frameMesh; this.frameSprite = frameSprite; @@ -62,46 +62,6 @@ final class FrameBakedModel implements BakedModel { this.translucentEmissiveMaterial = finder.blendMode(BlendMode.TRANSLUCENT).emissive(true).find(); } - @Override - public List getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) { - return Collections.emptyList(); // Renderer API makes this obsolete, so return no quads - } - - @Override - public boolean useAmbientOcclusion() { - return true; // we want the block to have a shadow depending on the adjacent blocks - } - - @Override - public boolean hasDepth() { - return false; - } - - @Override - public boolean isSideLit() { - return true; // we want the block to be lit from the side when rendered as an item - } - - @Override - public boolean isBuiltin() { - return false; - } - - @Override - public Sprite getParticleSprite() { - return this.frameSprite; - } - - @Override - public ModelTransformation getTransformation() { - return ModelHelper.MODEL_TRANSFORM_BLOCK; - } - - @Override - public ModelOverrideList getOverrides() { - return ModelOverrideList.EMPTY; - } - @Override public boolean isVanillaAdapter() { return false; @@ -142,7 +102,7 @@ public void emitItemQuads(ItemStack stack, Supplier randomSupplier, Rend // Emit a scaled-down fence for testing, trying both materials again. RenderMaterial material = stack.hasCustomName() ? translucentEmissiveMaterial : translucentMaterial; - ItemStack innerItem = Items.OAK_FENCE.getDefaultStack(); + ItemStack innerItem = Items.CRAFTING_TABLE.getDefaultStack(); BakedModel innerModel = MinecraftClient.getInstance().getItemRenderer().getModel(innerItem, null, null, 0); emitInnerQuads(context, material, () -> { @@ -187,4 +147,44 @@ private void emitInnerQuads(RenderContext context, RenderMaterial material, Runn // Let's not forget to pop the transform! context.popTransform(); } + + @Override + public List getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) { + return Collections.emptyList(); // Renderer API makes this obsolete, so return no quads + } + + @Override + public boolean useAmbientOcclusion() { + return true; // we want the block to have a shadow depending on the adjacent blocks + } + + @Override + public boolean hasDepth() { + return false; + } + + @Override + public boolean isSideLit() { + return true; // we want the block to be lit from the side when rendered as an item + } + + @Override + public boolean isBuiltin() { + return false; + } + + @Override + public Sprite getParticleSprite() { + return this.frameSprite; + } + + @Override + public ModelTransformation getTransformation() { + return ModelHelper.MODEL_TRANSFORM_BLOCK; + } + + @Override + public ModelOverrideList getOverrides() { + return ModelOverrideList.EMPTY; + } } diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameUnbakedModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameUnbakedModel.java new file mode 100644 index 0000000000..e4a52acede --- /dev/null +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/FrameUnbakedModel.java @@ -0,0 +1,118 @@ +/* + * 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.test.renderer.client; + +import java.util.Collection; +import java.util.Collections; +import java.util.function.Function; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.Baker; +import net.minecraft.client.render.model.ModelBakeSettings; +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.Direction; + +import net.fabricmc.fabric.api.renderer.v1.Renderer; +import net.fabricmc.fabric.api.renderer.v1.RendererAccess; +import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder; +import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView; +import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; + +public class FrameUnbakedModel implements UnbakedModel { + private static final SpriteIdentifier OBSIDIAN_SPRITE_ID = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new Identifier("block/obsidian")); + + @Override + public Collection getModelDependencies() { + return Collections.emptySet(); + } + + @Override + public void setParents(Function modelLoader) { + } + + /* + * Bake the model. + * In this case we can prebake the frame into a mesh, but will render the contained block when we draw the quads. + */ + @Nullable + @Override + public BakedModel bake(Baker baker, Function textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) { + // The renderer API may not have an implementation, so we should check if it exists. + if (!RendererAccess.INSTANCE.hasRenderer()) { + // No renderer implementation is present. + return null; + } + + Sprite obsidianSprite = textureGetter.apply(OBSIDIAN_SPRITE_ID); + + Renderer renderer = RendererAccess.INSTANCE.getRenderer(); + MeshBuilder builder = renderer.meshBuilder(); + QuadEmitter emitter = builder.getEmitter(); + + for (Direction direction : Direction.values()) { + // Draw outer frame + emitter.square(direction, 0.0F, 0.9F, 0.9F, 1.0F, 0.0F) + .spriteBake(obsidianSprite, MutableQuadView.BAKE_LOCK_UV) + .color(-1, -1, -1, -1) + .emit(); + + emitter.square(direction, 0.0F, 0.0F, 0.1F, 0.9F, 0.0F) + .spriteBake(obsidianSprite, MutableQuadView.BAKE_LOCK_UV) + .color(-1, -1, -1, -1) + .emit(); + + emitter.square(direction, 0.9F, 0.1F, 1.0F, 1.0F, 0.0F) + .spriteBake(obsidianSprite, MutableQuadView.BAKE_LOCK_UV) + .color(-1, -1, -1, -1) + .emit(); + + emitter.square(direction, 0.1F, 0.0F, 1.0F, 0.1F, 0.0F) + .spriteBake(obsidianSprite, MutableQuadView.BAKE_LOCK_UV) + .color(-1, -1, -1, -1) + .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(obsidianSprite, MutableQuadView.BAKE_LOCK_UV) + .color(-1, -1, -1, -1) + .emit(); + + emitter.square(direction, 0.0F, 0.0F, 0.1F, 0.9F, 0.9F) + .spriteBake(obsidianSprite, MutableQuadView.BAKE_LOCK_UV) + .color(-1, -1, -1, -1) + .emit(); + + emitter.square(direction, 0.9F, 0.1F, 1.0F, 1.0F, 0.9F) + .spriteBake(obsidianSprite, MutableQuadView.BAKE_LOCK_UV) + .color(-1, -1, -1, -1) + .emit(); + + emitter.square(direction, 0.1F, 0.0F, 1.0F, 0.1F, 0.9F) + .spriteBake(obsidianSprite, MutableQuadView.BAKE_LOCK_UV) + .color(-1, -1, -1, -1) + .emit(); + } + + return new FrameBakedModel(builder.build(), obsidianSprite); + } +} diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/ModelResolverImpl.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/ModelResolverImpl.java new file mode 100644 index 0000000000..e8b34d948b --- /dev/null +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/ModelResolverImpl.java @@ -0,0 +1,50 @@ +package net.fabricmc.fabric.test.renderer.client; + +import java.util.Set; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.api.client.model.loading.v1.ModelResolver; +import net.fabricmc.fabric.test.renderer.RendererTest; + +public class ModelResolverImpl implements ModelResolver { + private static final Set FRAME_MODEL_LOCATIONS = Set.of( + RendererTest.id("block/frame"), + RendererTest.id("item/frame"), + RendererTest.id("item/frame_multipart"), + RendererTest.id("item/frame_variant") + ); + + private static final Set PILLAR_MODEL_LOCATIONS = Set.of( + RendererTest.id("block/pillar"), + RendererTest.id("item/pillar") + ); + + private static final Set OCTAGONAL_COLUMN_MODEL_LOCATIONS = Set.of( + RendererTest.id("block/octagonal_column"), + RendererTest.id("item/octagonal_column") + ); + + @Override + @Nullable + public UnbakedModel resolveModel(Context context) { + Identifier id = context.id(); + + if (FRAME_MODEL_LOCATIONS.contains(id)) { + return new FrameUnbakedModel(); + } + + if (PILLAR_MODEL_LOCATIONS.contains(id)) { + return new PillarUnbakedModel(); + } + + if (OCTAGONAL_COLUMN_MODEL_LOCATIONS.contains(id)) { + return new OctagonalColumnUnbakedModel(); + } + + return null; + } +} diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OctagonalColumnUnbakedModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OctagonalColumnUnbakedModel.java new file mode 100644 index 0000000000..ba23475e41 --- /dev/null +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OctagonalColumnUnbakedModel.java @@ -0,0 +1,210 @@ +package net.fabricmc.fabric.test.renderer.client; + +import java.util.Collection; +import java.util.Collections; +import java.util.function.Function; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.Baker; +import net.minecraft.client.render.model.ModelBakeSettings; +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.api.renderer.v1.Renderer; +import net.fabricmc.fabric.api.renderer.v1.RendererAccess; +import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder; +import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; +import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder; +import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView; +import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; +import net.fabricmc.fabric.api.util.TriState; + +public class OctagonalColumnUnbakedModel implements UnbakedModel { + private static final SpriteIdentifier WHITE_CONCRETE_SPRITE_ID = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new Identifier("block/white_concrete")); + + // (B - A) is the side length of a regular octagon that fits in a unit square. + // The line from A to B is centered on the line from 0 to 1. + private static final float A = (float) (1 - Math.sqrt(2) / 2); + private static final float B = (float) (Math.sqrt(2) / 2); + + @Override + public Collection getModelDependencies() { + return Collections.emptySet(); + } + + @Override + public void setParents(Function modelLoader) { + } + + @Nullable + @Override + public BakedModel bake(Baker baker, Function textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) { + if (!RendererAccess.INSTANCE.hasRenderer()) { + return null; + } + + Sprite whiteConcreteSprite = textureGetter.apply(WHITE_CONCRETE_SPRITE_ID); + + Renderer renderer = RendererAccess.INSTANCE.getRenderer(); + MaterialFinder finder = renderer.materialFinder(); + RenderMaterial glintMaterial = finder.glint(TriState.TRUE).find(); + + MeshBuilder builder = renderer.meshBuilder(); + QuadEmitter emitter = builder.getEmitter(); + + // 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.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV); + emitter.color(-1, -1, -1, -1); + 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.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV); + emitter.color(-1, -1, -1, -1); + 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.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV); + emitter.color(-1, -1, -1, -1); + 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.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV); + emitter.color(-1, -1, -1, -1); + emitter.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.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV); + emitter.color(-1, -1, -1, -1); + 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.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV); + emitter.color(-1, -1, -1, -1); + 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.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV); + emitter.color(-1, -1, -1, -1); + 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.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV); + emitter.color(-1, -1, -1, -1); + emitter.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.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV); + emitter.material(glintMaterial); + emitter.color(-1, -1, -1, -1); + emitter.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); + emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV); + emitter.material(glintMaterial); + emitter.color(-1, -1, -1, -1); + emitter.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.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV); + emitter.material(glintMaterial); + emitter.color(-1, -1, -1, -1); + emitter.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); + emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV); + emitter.material(glintMaterial); + emitter.color(-1, -1, -1, -1); + emitter.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.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV); + emitter.material(glintMaterial); + emitter.color(-1, -1, -1, -1); + emitter.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); + emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV); + emitter.material(glintMaterial); + emitter.color(-1, -1, -1, -1); + emitter.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.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV); + emitter.material(glintMaterial); + emitter.color(-1, -1, -1, -1); + emitter.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); + emitter.spriteBake(whiteConcreteSprite, MutableQuadView.BAKE_LOCK_UV); + emitter.material(glintMaterial); + emitter.color(-1, -1, -1, -1); + emitter.emit(); + + return new SingleMeshBakedModel(builder.build(), whiteConcreteSprite); + } +} diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/simple/client/PillarBakedModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarBakedModel.java similarity index 73% rename from fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/simple/client/PillarBakedModel.java rename to fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarBakedModel.java index bccde93ddf..ae72b96420 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/simple/client/PillarBakedModel.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarBakedModel.java @@ -14,8 +14,9 @@ * limitations under the License. */ -package net.fabricmc.fabric.test.renderer.simple.client; +package net.fabricmc.fabric.test.renderer.client; +import java.util.Collections; import java.util.List; import java.util.function.Supplier; @@ -34,15 +35,11 @@ import net.minecraft.world.BlockRenderView; import net.fabricmc.fabric.api.block.v1.FabricBlockState; -import net.fabricmc.fabric.api.renderer.v1.RendererAccess; -import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder; -import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView; import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper; import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; -import net.fabricmc.fabric.api.util.TriState; -import net.fabricmc.fabric.test.renderer.simple.RendererTest; +import net.fabricmc.fabric.test.renderer.Registration; /** * Very crude implementation of a pillar block model that connects with pillars above and below. @@ -54,16 +51,9 @@ private enum ConnectedTexture { // alone, bottom, middle, top private final Sprite[] sprites; - private final RenderMaterial defaultMaterial; - private final RenderMaterial glintMaterial; public PillarBakedModel(Sprite[] sprites) { this.sprites = sprites; - - MaterialFinder finder = RendererAccess.INSTANCE.getRenderer().materialFinder(); - defaultMaterial = finder.find(); - finder.clear(); - glintMaterial = finder.glint(TriState.TRUE).find(); } @Override @@ -84,41 +74,35 @@ public void emitItemQuads(ItemStack stack, Supplier randomSupplier, Rend private void emitQuads(QuadEmitter emitter, @Nullable BlockRenderView blockView, @Nullable BlockState state, @Nullable BlockPos pos) { for (Direction side : Direction.values()) { ConnectedTexture texture = ConnectedTexture.ALONE; - RenderMaterial material = defaultMaterial; - - if (side.getAxis().isHorizontal()) { - if (blockView != null && state != null && pos != null) { - boolean connectAbove = canConnect(blockView, pos.offset(Direction.UP), side, state, pos); - boolean connectBelow = canConnect(blockView, pos.offset(Direction.DOWN), side, state, pos); - - if (connectAbove && connectBelow) { - texture = ConnectedTexture.MIDDLE; - } else if (connectAbove) { - texture = ConnectedTexture.BOTTOM; - } else if (connectBelow) { - texture = ConnectedTexture.TOP; - } - } - material = glintMaterial; + if (side.getAxis().isHorizontal() && blockView != null && state != null && pos != null) { + boolean connectAbove = canConnect(blockView, pos.offset(Direction.UP), side, state, pos); + boolean connectBelow = canConnect(blockView, pos.offset(Direction.DOWN), side, state, pos); + + if (connectAbove && connectBelow) { + texture = ConnectedTexture.MIDDLE; + } else if (connectAbove) { + texture = ConnectedTexture.BOTTOM; + } else if (connectBelow) { + texture = ConnectedTexture.TOP; + } } emitter.square(side, 0, 0, 1, 1, 0); emitter.spriteBake(sprites[texture.ordinal()], MutableQuadView.BAKE_LOCK_UV); emitter.color(-1, -1, -1, -1); - emitter.material(material); emitter.emit(); } } private static boolean canConnect(BlockRenderView blockView, BlockPos pos, Direction side, BlockState sourceState, BlockPos sourcePos) { // In this testmod we can't rely on injected interfaces - in normal mods the (FabricBlockState) cast will be unnecessary - return ((FabricBlockState) blockView.getBlockState(pos)).getAppearance(blockView, pos, side, sourceState, sourcePos).isOf(RendererTest.PILLAR); + return ((FabricBlockState) blockView.getBlockState(pos)).getAppearance(blockView, pos, side, sourceState, sourcePos).isOf(Registration.PILLAR_BLOCK); } @Override public List getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) { - return List.of(); + return Collections.emptyList(); } @Override diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/simple/client/PillarUnbakedModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarUnbakedModel.java similarity index 92% rename from fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/simple/client/PillarUnbakedModel.java rename to fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarUnbakedModel.java index 9a34e180e7..b94fda0c5e 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/simple/client/PillarUnbakedModel.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarUnbakedModel.java @@ -14,9 +14,10 @@ * limitations under the License. */ -package net.fabricmc.fabric.test.renderer.simple.client; +package net.fabricmc.fabric.test.renderer.client; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.function.Function; import java.util.stream.Stream; @@ -32,7 +33,7 @@ import net.minecraft.screen.PlayerScreenHandler; import net.minecraft.util.Identifier; -import net.fabricmc.fabric.test.renderer.simple.RendererTest; +import net.fabricmc.fabric.test.renderer.RendererTest; public class PillarUnbakedModel implements UnbakedModel { private static final List SPRITES = Stream.of("alone", "bottom", "middle", "top") @@ -41,7 +42,7 @@ public class PillarUnbakedModel implements UnbakedModel { @Override public Collection getModelDependencies() { - return List.of(); + return Collections.emptySet(); } @Override diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/simple/client/RendererClientTest.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/RendererClientTest.java similarity index 55% rename from fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/simple/client/RendererClientTest.java rename to fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/RendererClientTest.java index 1e45c93a9c..79645dffe0 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/simple/client/RendererClientTest.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/RendererClientTest.java @@ -14,51 +14,27 @@ * limitations under the License. */ -package net.fabricmc.fabric.test.renderer.simple.client; - -import static net.fabricmc.fabric.test.renderer.simple.RendererTest.id; - -import java.util.HashSet; -import java.util.Set; +package net.fabricmc.fabric.test.renderer.client; import net.minecraft.client.render.RenderLayer; -import net.minecraft.registry.Registries; -import net.minecraft.util.Identifier; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin; -import net.fabricmc.fabric.test.renderer.simple.FrameBlock; -import net.fabricmc.fabric.test.renderer.simple.RendererTest; +import net.fabricmc.fabric.test.renderer.FrameBlock; +import net.fabricmc.fabric.test.renderer.Registration; public final class RendererClientTest implements ClientModInitializer { - private static final Set FRAME_MODELS = new HashSet<>(); - @Override public void onInitializeClient() { - for (FrameBlock frameBlock : RendererTest.FRAMES) { + ModelLoadingPlugin.register(pluginContext -> { + pluginContext.resolveModel().register(new ModelResolverImpl()); + }); + + for (FrameBlock frameBlock : Registration.FRAME_BLOCKS) { // We don't specify a material for the frame mesh, // so it will use the default material, i.e. the one from BlockRenderLayerMap. BlockRenderLayerMap.INSTANCE.putBlock(frameBlock, RenderLayer.getCutoutMipped()); - - String itemPath = Registries.ITEM.getId(frameBlock.asItem()).getPath(); - FRAME_MODELS.add(id("item/" + itemPath)); } - - FRAME_MODELS.add(id("block/frame")); - - ModelLoadingPlugin.register(pluginContext -> { - pluginContext.resolveModel().register(context -> { - if (FRAME_MODELS.contains(context.id())) { - return new FrameUnbakedModel(); - } - - return null; - }); - - pluginContext.registerBlockStateResolver(RendererTest.PILLAR, context -> { - context.setModel(context.block().getDefaultState(), new PillarUnbakedModel()); - }); - }); } } diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/SingleMeshBakedModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/SingleMeshBakedModel.java new file mode 100644 index 0000000000..feac7ad18a --- /dev/null +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/SingleMeshBakedModel.java @@ -0,0 +1,88 @@ +package net.fabricmc.fabric.test.renderer.client; + +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.block.BlockState; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.BakedQuad; +import net.minecraft.client.render.model.json.ModelOverrideList; +import net.minecraft.client.render.model.json.ModelTransformation; +import net.minecraft.client.texture.Sprite; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.BlockRenderView; + +import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; +import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper; +import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; + +public class SingleMeshBakedModel implements BakedModel { + private final Mesh mesh; + private final Sprite particleSprite; + + public SingleMeshBakedModel(Mesh mesh, Sprite particleSprite) { + this.mesh = mesh; + this.particleSprite = particleSprite; + } + + @Override + public boolean isVanillaAdapter() { + return false; + } + + @Override + public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { + mesh.outputTo(context.getEmitter()); + } + + @Override + public void emitItemQuads(ItemStack stack, Supplier randomSupplier, RenderContext context) { + mesh.outputTo(context.getEmitter()); + } + + @Override + public List getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) { + return Collections.emptyList(); + } + + @Override + public boolean useAmbientOcclusion() { + return true; + } + + @Override + public boolean hasDepth() { + return false; + } + + @Override + public boolean isSideLit() { + return true; + } + + @Override + public boolean isBuiltin() { + return false; + } + + @Override + public Sprite getParticleSprite() { + return particleSprite; + } + + @Override + public ModelTransformation getTransformation() { + return ModelHelper.MODEL_TRANSFORM_BLOCK; + } + + @Override + public ModelOverrideList getOverrides() { + return ModelOverrideList.EMPTY; + } +} diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/simple/client/FrameUnbakedModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/simple/client/FrameUnbakedModel.java deleted file mode 100644 index 43b880b118..0000000000 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/simple/client/FrameUnbakedModel.java +++ /dev/null @@ -1,120 +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.test.renderer.simple.client; - -import java.util.Collection; -import java.util.Collections; -import java.util.function.Function; - -import org.jetbrains.annotations.Nullable; - -import net.minecraft.client.render.model.BakedModel; -import net.minecraft.client.render.model.Baker; -import net.minecraft.client.render.model.ModelBakeSettings; -import net.minecraft.client.render.model.UnbakedModel; -import net.minecraft.client.texture.Sprite; -import net.minecraft.client.texture.SpriteAtlasTexture; -import net.minecraft.client.util.SpriteIdentifier; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.Direction; - -import net.fabricmc.fabric.api.renderer.v1.Renderer; -import net.fabricmc.fabric.api.renderer.v1.RendererAccess; -import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder; -import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView; -import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; - -final class FrameUnbakedModel implements UnbakedModel { - FrameUnbakedModel() { - } - - @Override - public Collection getModelDependencies() { - return Collections.emptySet(); - } - - @Override - public void setParents(Function function) { - } - - /* - * Bake the model. - * In this case we can prebake the frame into a mesh, but will render the contained block when we draw the quads. - */ - @Nullable - @Override - public BakedModel bake(Baker baker, Function textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) { - // The renderer api may not have an implementation. - // For this reason we will just null check the renderer impl - if (RendererAccess.INSTANCE.hasRenderer()) { - Renderer renderer = RendererAccess.INSTANCE.getRenderer(); - MeshBuilder builder = renderer.meshBuilder(); - QuadEmitter emitter = builder.getEmitter(); - // TODO: Just some random texture to get a missing texture, we should get a proper texture soon - Sprite frameSprite = textureGetter.apply(new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new Identifier("foo:foo"))); - - for (Direction direction : Direction.values()) { - // Draw outer frame - emitter.square(direction, 0.0F, 0.9F, 0.9F, 1.0F, 0.0F) - .spriteBake(frameSprite, MutableQuadView.BAKE_LOCK_UV) - .color(-1, -1, -1, -1) - .emit(); - - emitter.square(direction, 0.0F, 0.0F, 0.1F, 0.9F, 0.0F) - .spriteBake(frameSprite, MutableQuadView.BAKE_LOCK_UV) - .color(-1, -1, -1, -1) - .emit(); - - emitter.square(direction, 0.9F, 0.1F, 1.0F, 1.0F, 0.0F) - .spriteBake(frameSprite, MutableQuadView.BAKE_LOCK_UV) - .color(-1, -1, -1, -1) - .emit(); - - emitter.square(direction, 0.1F, 0.0F, 1.0F, 0.1F, 0.0F) - .spriteBake(frameSprite, MutableQuadView.BAKE_LOCK_UV) - .color(-1, -1, -1, -1) - .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(frameSprite, MutableQuadView.BAKE_LOCK_UV) - .color(-1, -1, -1, -1) - .emit(); - - emitter.square(direction, 0.0F, 0.0F, 0.1F, 0.9F, 0.9F) - .spriteBake(frameSprite, MutableQuadView.BAKE_LOCK_UV) - .color(-1, -1, -1, -1) - .emit(); - - emitter.square(direction, 0.9F, 0.1F, 1.0F, 1.0F, 0.9F) - .spriteBake(frameSprite, MutableQuadView.BAKE_LOCK_UV) - .color(-1, -1, -1, -1) - .emit(); - - emitter.square(direction, 0.1F, 0.0F, 1.0F, 0.1F, 0.9F) - .spriteBake(frameSprite, MutableQuadView.BAKE_LOCK_UV) - .color(-1, -1, -1, -1) - .emit(); - } - - return new FrameBakedModel(builder.build(), frameSprite); - } - - // No renderer implementation is present. - return null; - } -} diff --git a/fabric-renderer-api-v1/src/testmodClient/resources/assets/fabric-renderer-api-v1-testmod/blockstates/octagonal_column.json b/fabric-renderer-api-v1/src/testmodClient/resources/assets/fabric-renderer-api-v1-testmod/blockstates/octagonal_column.json new file mode 100644 index 0000000000..f62ea8ad6b --- /dev/null +++ b/fabric-renderer-api-v1/src/testmodClient/resources/assets/fabric-renderer-api-v1-testmod/blockstates/octagonal_column.json @@ -0,0 +1,5 @@ +{ + "variants": { + "": { "model": "fabric-renderer-api-v1-testmod:block/octagonal_column" } + } +} diff --git a/fabric-renderer-api-v1/src/testmodClient/resources/assets/fabric-renderer-api-v1-testmod/blockstates/pillar.json b/fabric-renderer-api-v1/src/testmodClient/resources/assets/fabric-renderer-api-v1-testmod/blockstates/pillar.json new file mode 100644 index 0000000000..53bec1ded6 --- /dev/null +++ b/fabric-renderer-api-v1/src/testmodClient/resources/assets/fabric-renderer-api-v1-testmod/blockstates/pillar.json @@ -0,0 +1,5 @@ +{ + "variants": { + "": { "model": "fabric-renderer-api-v1-testmod:block/pillar" } + } +} From 717d5dcf84e7dae26ca5aef1510261de8820a5df Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Thu, 20 Jul 2023 10:52:37 -0600 Subject: [PATCH 3/6] Fix crumbling on 45 degree faces - Fix checkstyle - Give octagonal column a non-zero hardness --- .../client/OverlayVertexConsumerMixin.java | 32 +++++++++++++++++++ .../fabric-renderer-api-v1.mixins.json | 3 +- .../fabric/test/renderer/Registration.java | 2 +- .../fabric/test/renderer/RendererTest.java | 3 +- 4 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/renderer/client/OverlayVertexConsumerMixin.java diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/renderer/client/OverlayVertexConsumerMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/renderer/client/OverlayVertexConsumerMixin.java new file mode 100644 index 0000000000..0dd49e7d68 --- /dev/null +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/renderer/client/OverlayVertexConsumerMixin.java @@ -0,0 +1,32 @@ +package net.fabricmc.fabric.mixin.renderer.client; + +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.Redirect; + +import net.minecraft.client.render.OverlayVertexConsumer; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathConstants; + +@Mixin(OverlayVertexConsumer.class) +public class OverlayVertexConsumerMixin { + @Unique + private static final Direction[] DIRECTIONS = Direction.values(); + + @Redirect(method = "next()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/math/Direction;getFacing(FFF)Lnet/minecraft/util/math/Direction;")) + private Direction redirectGetFacing(float x, float y, float z) { + Direction closestDir = Direction.NORTH; + float maxDot = 1.4E-45F; + + for (Direction direction : DIRECTIONS) { + float dot = x * direction.getOffsetX() + y * direction.getOffsetY() + z * direction.getOffsetZ(); + if (dot > maxDot + MathConstants.EPSILON) { + maxDot = dot; + closestDir = direction; + } + } + + return closestDir; + } +} 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 075e074683..f12cca5091 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 @@ -6,7 +6,8 @@ "client.BakedModelMixin", "client.MultipartBakedModelMixin", "client.WeightedBakedModelMixin", - "client.SpriteAtlasTextureMixin" + "client.SpriteAtlasTextureMixin", + "client.OverlayVertexConsumerMixin" ], "injectors": { "defaultRequire": 1 diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java index 229b83058d..efc3a6007b 100644 --- a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java @@ -16,7 +16,7 @@ public final class Registration { public static final FrameBlock FRAME_MULTIPART_BLOCK = register("frame_multipart", new FrameBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque())); public static final FrameBlock FRAME_VARIANT_BLOCK = register("frame_variant", new FrameBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque())); public static final Block PILLAR_BLOCK = register("pillar", new Block(FabricBlockSettings.create())); - public static final Block OCTAGONAL_COLUMN_BLOCK = register("octagonal_column", new Block(FabricBlockSettings.create().nonOpaque())); + public static final Block OCTAGONAL_COLUMN_BLOCK = register("octagonal_column", new Block(FabricBlockSettings.create().nonOpaque().strength(1.8F))); public static final FrameBlock[] FRAME_BLOCKS = new FrameBlock[] { FRAME_BLOCK, diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/RendererTest.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/RendererTest.java index fc26a233a7..0a213d98ca 100644 --- a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/RendererTest.java +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/RendererTest.java @@ -20,13 +20,12 @@ import net.fabricmc.api.ModInitializer; - /** * The testmod for the Fabric Renderer API. These tests are used to validate that * Indigo's implementation is correct, but they may also be useful for other * implementations of the Fabric Renderer API. * - *

Tests + *

Tests

* *
    *
  • Frame blocks displays another block inside, scaled down and made translucent. From 616f0fd66f5fef3a5176bacc334e9c4efdc2b16f Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Thu, 20 Jul 2023 12:42:21 -0600 Subject: [PATCH 4/6] Fix checkstyle --- .../client/OverlayVertexConsumerMixin.java | 17 +++++++++++++++++ .../fabric/test/renderer/Registration.java | 16 ++++++++++++++++ .../test/renderer/client/ModelResolverImpl.java | 16 ++++++++++++++++ .../client/OctagonalColumnUnbakedModel.java | 16 ++++++++++++++++ .../renderer/client/SingleMeshBakedModel.java | 16 ++++++++++++++++ 5 files changed, 81 insertions(+) diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/renderer/client/OverlayVertexConsumerMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/renderer/client/OverlayVertexConsumerMixin.java index 0dd49e7d68..e613d809eb 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/renderer/client/OverlayVertexConsumerMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/renderer/client/OverlayVertexConsumerMixin.java @@ -1,3 +1,19 @@ +/* + * 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.renderer.client; import org.spongepowered.asm.mixin.Mixin; @@ -21,6 +37,7 @@ private Direction redirectGetFacing(float x, float y, float z) { for (Direction direction : DIRECTIONS) { float dot = x * direction.getOffsetX() + y * direction.getOffsetY() + z * direction.getOffsetZ(); + if (dot > maxDot + MathConstants.EPSILON) { maxDot = dot; closestDir = direction; diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java index efc3a6007b..7c72d37596 100644 --- a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/Registration.java @@ -1,3 +1,19 @@ +/* + * 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.test.renderer; import net.minecraft.block.Block; diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/ModelResolverImpl.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/ModelResolverImpl.java index e8b34d948b..5440d5f3b2 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/ModelResolverImpl.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/ModelResolverImpl.java @@ -1,3 +1,19 @@ +/* + * 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.test.renderer.client; import java.util.Set; diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OctagonalColumnUnbakedModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OctagonalColumnUnbakedModel.java index ba23475e41..7d63f22c9f 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OctagonalColumnUnbakedModel.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/OctagonalColumnUnbakedModel.java @@ -1,3 +1,19 @@ +/* + * 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.test.renderer.client; import java.util.Collection; diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/SingleMeshBakedModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/SingleMeshBakedModel.java index feac7ad18a..26b1d3b783 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/SingleMeshBakedModel.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/SingleMeshBakedModel.java @@ -1,3 +1,19 @@ +/* + * 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.test.renderer.client; import java.util.Collections; From abbaf729ad9dfaae37911980907989c0a307b13d Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Sat, 22 Jul 2023 13:59:11 -0600 Subject: [PATCH 5/6] Improve PillarBakedModel to fully support custom block appearance --- .../renderer/client/PillarBakedModel.java | 47 ++++++++++++++----- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarBakedModel.java b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarBakedModel.java index ae72b96420..6690e3aee5 100644 --- a/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarBakedModel.java +++ b/fabric-renderer-api-v1/src/testmodClient/java/net/fabricmc/fabric/test/renderer/client/PillarBakedModel.java @@ -63,21 +63,17 @@ public boolean isVanillaAdapter() { @Override public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { - emitQuads(context.getEmitter(), blockView, state, pos); - } - - @Override - public void emitItemQuads(ItemStack stack, Supplier randomSupplier, RenderContext context) { - emitQuads(context.getEmitter(), null, null, null); - } + QuadEmitter emitter = context.getEmitter(); + // Do not use the passed state to ensure that this model connects + // to and from blocks with a custom appearance correctly. + BlockState worldState = blockView.getBlockState(pos); - private void emitQuads(QuadEmitter emitter, @Nullable BlockRenderView blockView, @Nullable BlockState state, @Nullable BlockPos pos) { for (Direction side : Direction.values()) { ConnectedTexture texture = ConnectedTexture.ALONE; - if (side.getAxis().isHorizontal() && blockView != null && state != null && pos != null) { - boolean connectAbove = canConnect(blockView, pos.offset(Direction.UP), side, state, pos); - boolean connectBelow = canConnect(blockView, pos.offset(Direction.DOWN), side, state, pos); + if (side.getAxis().isHorizontal()) { + boolean connectAbove = canConnect(blockView, worldState, pos, pos.offset(Direction.UP), side); + boolean connectBelow = canConnect(blockView, worldState, pos, pos.offset(Direction.DOWN), side); if (connectAbove && connectBelow) { texture = ConnectedTexture.MIDDLE; @@ -95,9 +91,34 @@ private void emitQuads(QuadEmitter emitter, @Nullable BlockRenderView blockView, } } - private static boolean canConnect(BlockRenderView blockView, BlockPos pos, Direction side, BlockState sourceState, BlockPos sourcePos) { + @Override + public void emitItemQuads(ItemStack stack, Supplier randomSupplier, RenderContext context) { + QuadEmitter emitter = context.getEmitter(); + + for (Direction side : Direction.values()) { + emitter.square(side, 0, 0, 1, 1, 0); + emitter.spriteBake(sprites[ConnectedTexture.ALONE.ordinal()], MutableQuadView.BAKE_LOCK_UV); + emitter.color(-1, -1, -1, -1); + emitter.emit(); + } + } + + private static boolean canConnect(BlockRenderView blockView, BlockState originState, BlockPos originPos, BlockPos otherPos, Direction side) { + BlockState otherState = blockView.getBlockState(otherPos); // In this testmod we can't rely on injected interfaces - in normal mods the (FabricBlockState) cast will be unnecessary - return ((FabricBlockState) blockView.getBlockState(pos)).getAppearance(blockView, pos, side, sourceState, sourcePos).isOf(Registration.PILLAR_BLOCK); + BlockState originAppearance = ((FabricBlockState) originState).getAppearance(blockView, originPos, side, otherState, otherPos); + + if (!originAppearance.isOf(Registration.PILLAR_BLOCK)) { + return false; + } + + BlockState otherAppearance = ((FabricBlockState) otherState).getAppearance(blockView, otherPos, side, originState, originPos); + + if (!otherAppearance.isOf(Registration.PILLAR_BLOCK)) { + return false; + } + + return true; } @Override From 3a3e47655f87083e9e2a10b4179d21d7474c5ee6 Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Wed, 2 Aug 2023 17:07:56 -0600 Subject: [PATCH 6/6] Explain OverlayVertexConsumer fix --- .../renderer/client/OverlayVertexConsumerMixin.java | 11 +++++++++++ .../fabricmc/fabric/test/renderer/RendererTest.java | 7 +++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/renderer/client/OverlayVertexConsumerMixin.java b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/renderer/client/OverlayVertexConsumerMixin.java index e613d809eb..2c90cb32f5 100644 --- a/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/renderer/client/OverlayVertexConsumerMixin.java +++ b/fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/mixin/renderer/client/OverlayVertexConsumerMixin.java @@ -30,6 +30,17 @@ public class OverlayVertexConsumerMixin { @Unique private static final Direction[] DIRECTIONS = Direction.values(); + /* + The original method call is used to get the closest axis-aligned direction of the world-space + normal vector for a certain face. The world-space normal vector is computed using matrices + that change when the camera values change. Due to precision errors during matrix + multiplication, the computed world-space normal of a face will not remain constant, so the + closest axis-aligned direction may flicker. This issue only affects faces that are directly + between two axis-aligned directions (45 degree faces) or three axis-aligned directions. + + The fix involves requiring the dot product of each axis-aligned direction to be a small + amount greater than the previous maximum dot product to be set as the new maximum. + */ @Redirect(method = "next()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/math/Direction;getFacing(FFF)Lnet/minecraft/util/math/Direction;")) private Direction redirectGetFacing(float x, float y, float z) { Direction closestDir = Direction.NORTH; diff --git a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/RendererTest.java b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/RendererTest.java index 0a213d98ca..bdd6e22bb9 100644 --- a/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/RendererTest.java +++ b/fabric-renderer-api-v1/src/testmod/java/net/fabricmc/fabric/test/renderer/RendererTest.java @@ -28,16 +28,15 @@ *

    Tests

    * *
      - *
    • Frame blocks displays another block inside, scaled down and made translucent. - * Blocks that provide a block entity cannot be placed inside frames. This also tests - * that mesh builders and meshes work properly. + *
    • Frame blocks display another block inside, scaled down and made translucent. + * Blocks that provide a block entity cannot be placed inside frames. * *
    • Pillars connect vertically with each other by changing textures. They also * connect vertically to frame blocks containing a pillar, and vice versa. * *
    • Octagonal columns have irregular faces to test enhanced AO and normal shade. The * octagonal item column has glint force enabled on all faces except the top and bottom - * faces. This also tests that mesh builders and meshes work properly. + * faces. *
    */ public final class RendererTest implements ModInitializer {