diff --git a/build.gradle b/build.gradle index 5e124c49f..d008c15e4 100644 --- a/build.gradle +++ b/build.gradle @@ -28,6 +28,13 @@ repositories { maven { url 'https://maven.parchmentmc.org/' } + maven { + name 'Modrinth' + url 'https://api.modrinth.com/maven' + } + maven { + url 'https://maven.vram.io' + } } dependencies { @@ -44,6 +51,8 @@ dependencies { modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_version}" implementation 'com.google.code.findbugs:jsr305:3.0.2' + modCompileOnly 'maven.modrinth:indium:1.0.2-alpha1+mc1.18' + modCompileOnly 'io.vram:frex-fabric-mc118:6.0.229' //implementation 'org.joml:joml:1.10.1' } diff --git a/src/main/java/com/jozufozu/flywheel/core/PartialModel.java b/src/main/java/com/jozufozu/flywheel/core/PartialModel.java index 572df712c..3e1fd338f 100644 --- a/src/main/java/com/jozufozu/flywheel/core/PartialModel.java +++ b/src/main/java/com/jozufozu/flywheel/core/PartialModel.java @@ -44,7 +44,7 @@ public class PartialModel { public static void onModelRegistry(ResourceManager manager, Consumer out) { for (PartialModel partial : ALL) - out.accept(partial.modelLocation); + out.accept(partial.getLocation()); tooLate = true; } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/BakedModelModel.java b/src/main/java/com/jozufozu/flywheel/core/model/BakedModelModel.java index 19fdfd8ef..b01dc3476 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/BakedModelModel.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/BakedModelModel.java @@ -21,6 +21,7 @@ import net.minecraft.client.resources.model.BakedModel; import net.minecraft.core.Direction; import net.minecraft.core.Vec3i; +// TODO Fabric public class BakedModelModel implements Model { // DOWN, UP, NORTH, SOUTH, WEST, EAST, null private static final Direction[] dirs; @@ -44,7 +45,6 @@ public class BakedModelModel implements Model { for (Direction dir : dirs) { random.setSeed(42); - // TODO List quads = model.getQuads(null, dir, random/*, VirtualEmptyModelData.INSTANCE*/); numQuads += quads.size(); @@ -69,7 +69,6 @@ public class BakedModelModel implements Model { for (Direction dir : dirs) { random.setSeed(42); - // TODO List quads = model.getQuads(null, dir, random/*, VirtualEmptyModelData.INSTANCE*/); for (BakedQuad bakedQuad : quads) { diff --git a/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java b/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java index 01b154038..5ac5a3558 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java @@ -4,6 +4,9 @@ import java.util.Arrays; import java.util.Collection; import java.util.Random; +import com.jozufozu.flywheel.fabric.model.CullingBakedModel; +import com.jozufozu.flywheel.fabric.model.DefaultLayerFilteringBakedModel; +import com.jozufozu.flywheel.fabric.model.LayerFilteringBakedModel; import com.jozufozu.flywheel.util.Lazy; import com.jozufozu.flywheel.util.VirtualEmptyBlockGetter; import com.mojang.blaze3d.vertex.BufferBuilder; @@ -12,7 +15,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexFormat; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.ItemBlockRenderTypes; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.BlockModelShaper; import net.minecraft.client.renderer.block.ModelBlockRenderer; @@ -25,7 +27,6 @@ import net.minecraft.world.level.block.RenderShape; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; -// TODO public class ModelUtil { private static final Lazy MODEL_RENDERER = Lazy.of(() -> new ModelBlockRenderer(Minecraft.getInstance().getBlockColors())); @@ -50,8 +51,9 @@ public class ModelUtil { // .collect(Collectors.toList()); builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); + model = DefaultLayerFilteringBakedModel.wrap(model); blockRenderer.tesselateBlock(VirtualEmptyBlockGetter.INSTANCE, model, referenceState, BlockPos.ZERO, ms, builder, - true, new Random(), 42, OverlayTexture.NO_OVERLAY); + false, new Random(), 42, OverlayTexture.NO_OVERLAY); builder.end(); return builder; } @@ -65,27 +67,25 @@ public class ModelUtil { BufferBuilder builder = new BufferBuilder(512); builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); -// ForgeHooksClient.setRenderType(layer); ModelBlockRenderer.enableCaching(); for (StructureTemplate.StructureBlockInfo info : blocks) { BlockState state = info.state; if (state.getRenderShape() != RenderShape.MODEL) continue; -// if (!ItemBlockRenderTypes.canRenderInLayer(state, layer)) - if (ItemBlockRenderTypes.getChunkRenderType(state) != layer) - continue; BlockPos pos = info.pos; ms.pushPose(); ms.translate(pos.getX(), pos.getY(), pos.getZ()); - modelRenderer.tesselateBlock(renderWorld, blockModels.getBlockModel(state), state, pos, ms, builder, + BakedModel model = blockModels.getBlockModel(state); + model = CullingBakedModel.wrap(model); + model = LayerFilteringBakedModel.wrap(model, layer); + modelRenderer.tesselateBlock(renderWorld, model, state, pos, ms, builder, true, random, 42, OverlayTexture.NO_OVERLAY); ms.popPose(); } ModelBlockRenderer.clearCache(); -// ForgeHooksClient.setRenderType(null); builder.end(); return builder; diff --git a/src/main/java/com/jozufozu/flywheel/fabric/model/CullingBakedModel.java b/src/main/java/com/jozufozu/flywheel/fabric/model/CullingBakedModel.java new file mode 100644 index 000000000..a96d7cf04 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/fabric/model/CullingBakedModel.java @@ -0,0 +1,61 @@ +package com.jozufozu.flywheel.fabric.model; + +import java.util.Random; +import java.util.function.Supplier; + +import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel; +import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; +import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; + +public class CullingBakedModel extends ForwardingBakedModel { + private static final ThreadLocal THREAD_LOCAL = ThreadLocal.withInitial(CullingBakedModel::new); + + protected int completionFlags = 0; + protected int resultFlags = 0; + + protected final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos(); + + public static BakedModel wrap(BakedModel model) { + if (!FabricModelUtil.FREX_LOADED && !((FabricBakedModel) model).isVanillaAdapter()) { + CullingBakedModel wrapper = THREAD_LOCAL.get(); + wrapper.wrapped = model; + return wrapper; + } + return model; + } + + protected CullingBakedModel() { + } + + @Override + public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { + completionFlags = 0; + resultFlags = 0; + context.pushTransform(quad -> { + Direction cullFace = quad.cullFace(); + if (cullFace != null) { + int mask = 1 << cullFace.ordinal(); + if ((completionFlags & mask) == 0) { + completionFlags |= mask; + if (Block.shouldRenderFace(state, blockView, pos, cullFace, mutablePos.setWithOffset(pos, cullFace))) { + resultFlags |= mask; + return true; + } else { + return false; + } + } else { + return (resultFlags & mask) != 0; + } + } + return true; + }); + super.emitBlockQuads(blockView, state, pos, randomSupplier, context); + context.popTransform(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/fabric/model/DefaultLayerFilteringBakedModel.java b/src/main/java/com/jozufozu/flywheel/fabric/model/DefaultLayerFilteringBakedModel.java new file mode 100644 index 000000000..5626fe5ae --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/fabric/model/DefaultLayerFilteringBakedModel.java @@ -0,0 +1,49 @@ +package com.jozufozu.flywheel.fabric.model; + +import java.util.Random; +import java.util.function.Supplier; + +import net.fabricmc.fabric.api.renderer.v1.material.BlendMode; +import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView; +import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel; +import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; +import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; + +public class DefaultLayerFilteringBakedModel extends ForwardingBakedModel { + private static final ThreadLocal THREAD_LOCAL = ThreadLocal.withInitial(DefaultLayerFilteringBakedModel::new); + + public static BakedModel wrap(BakedModel model) { + if (!((FabricBakedModel) model).isVanillaAdapter()) { + DefaultLayerFilteringBakedModel wrapper = THREAD_LOCAL.get(); + wrapper.wrapped = model; + return wrapper; + } + return model; + } + + protected DefaultLayerFilteringBakedModel() { + } + + @Override + public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { + context.pushTransform(DefaultLayerFilteringBakedModel::hasDefaultBlendMode); + super.emitBlockQuads(blockView, state, pos, randomSupplier, context); + context.popTransform(); + } + + @Override + public void emitItemQuads(ItemStack stack, Supplier randomSupplier, RenderContext context) { + context.pushTransform(DefaultLayerFilteringBakedModel::hasDefaultBlendMode); + super.emitItemQuads(stack, randomSupplier, context); + context.popTransform(); + } + + public static boolean hasDefaultBlendMode(QuadView quad) { + return FabricModelUtil.getBlendMode(quad.material()) == BlendMode.DEFAULT; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/fabric/model/FabricModelUtil.java b/src/main/java/com/jozufozu/flywheel/fabric/model/FabricModelUtil.java new file mode 100644 index 000000000..6af874135 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/fabric/model/FabricModelUtil.java @@ -0,0 +1,67 @@ +package com.jozufozu.flywheel.fabric.model; + +import java.lang.reflect.Field; + +import com.jozufozu.flywheel.Flywheel; + +import io.vram.frex.api.material.MaterialConstants; +import io.vram.frex.fabric.compat.FabricMaterial; +import net.fabricmc.fabric.api.renderer.v1.material.BlendMode; +import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; +import net.fabricmc.fabric.impl.client.indigo.renderer.RenderMaterialImpl; +import net.fabricmc.loader.api.FabricLoader; + +public class FabricModelUtil { + public static final boolean INDIUM_LOADED = FabricLoader.getInstance().isModLoaded("indium"); + public static final boolean FREX_LOADED = FabricLoader.getInstance().isModLoaded("frex"); + + private static final BlendModeGetter BLEND_MODE_GETTER = createBlendModeGetter(); + + private static BlendModeGetter createBlendModeGetter() { + if (FREX_LOADED) { + try { + Field frexMaterialField = FabricMaterial.class.getDeclaredField("wrapped"); + frexMaterialField.setAccessible(true); + return material -> { + try { + io.vram.frex.api.material.RenderMaterial frexMaterial = (io.vram.frex.api.material.RenderMaterial) frexMaterialField.get(material); + return switch (frexMaterial.preset()) { + case MaterialConstants.PRESET_DEFAULT -> BlendMode.DEFAULT; + case MaterialConstants.PRESET_SOLID -> BlendMode.SOLID; + case MaterialConstants.PRESET_CUTOUT_MIPPED -> BlendMode.CUTOUT_MIPPED; + case MaterialConstants.PRESET_CUTOUT -> BlendMode.CUTOUT; + case MaterialConstants.PRESET_TRANSLUCENT -> BlendMode.TRANSLUCENT; + case MaterialConstants.PRESET_NONE -> { + if (frexMaterial.transparency() != MaterialConstants.TRANSPARENCY_NONE) { + yield BlendMode.TRANSLUCENT; + } else if (frexMaterial.cutout() == MaterialConstants.CUTOUT_NONE) { + yield BlendMode.SOLID; + } else { + yield frexMaterial.unmipped() ? BlendMode.CUTOUT : BlendMode.CUTOUT_MIPPED; + } + } + default -> BlendMode.DEFAULT; + }; + } catch (Exception e) { + } + return BlendMode.DEFAULT; + }; + } catch (Exception e) { + Flywheel.log.error("Detected FREX but failed to load wrapper field.", e); + return material -> BlendMode.DEFAULT; + } + } else if (INDIUM_LOADED) { + return material -> ((link.infra.indium.renderer.RenderMaterialImpl) material).blendMode(0); + } else { + return material -> ((RenderMaterialImpl) material).blendMode(0); + } + } + + public static BlendMode getBlendMode(RenderMaterial material) { + return BLEND_MODE_GETTER.getBlendMode(material); + } + + private interface BlendModeGetter { + BlendMode getBlendMode(RenderMaterial material); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/fabric/model/LayerFilteringBakedModel.java b/src/main/java/com/jozufozu/flywheel/fabric/model/LayerFilteringBakedModel.java new file mode 100644 index 000000000..5bf88755a --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/fabric/model/LayerFilteringBakedModel.java @@ -0,0 +1,55 @@ +package com.jozufozu.flywheel.fabric.model; + +import java.util.Random; +import java.util.function.Supplier; + +import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel; +import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; +import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; +import net.minecraft.client.renderer.ItemBlockRenderTypes; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; + +public class LayerFilteringBakedModel extends ForwardingBakedModel { + private static final ThreadLocal THREAD_LOCAL = ThreadLocal.withInitial(LayerFilteringBakedModel::new); + + protected RenderType targetLayer; + + public static BakedModel wrap(BakedModel model, RenderType layer) { + LayerFilteringBakedModel wrapper = THREAD_LOCAL.get(); + wrapper.wrapped = model; + wrapper.targetLayer = layer; + return wrapper; + } + + protected LayerFilteringBakedModel() { + } + + @Override + public boolean isVanillaAdapter() { + return false; + } + + @Override + public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { + RenderType defaultLayer = ItemBlockRenderTypes.getChunkRenderType(state); + if (((FabricBakedModel) wrapped).isVanillaAdapter()) { + if (defaultLayer == targetLayer) { + super.emitBlockQuads(blockView, state, pos, randomSupplier, context); + } + } else { + context.pushTransform(quad -> { + RenderType quadLayer = FabricModelUtil.getBlendMode(quad.material()).blockRenderLayer; + if (quadLayer == null) { + quadLayer = defaultLayer; + } + return quadLayer == targetLayer; + }); + super.emitBlockQuads(blockView, state, pos, randomSupplier, context); + context.popTransform(); + } + } +}