feat: more axiom support (connected textures and culling in selections) + newer version

This commit is contained in:
Adrien1106 2024-06-13 22:51:05 +02:00
parent ce650abc76
commit b88a4abfe5
12 changed files with 364 additions and 110 deletions

View File

@ -45,7 +45,10 @@ public class DoubleRetexturingBakedModel extends ForwardingBakedModel implements
} }
@Override @Override
public void emitBlockQuads(BlockRenderView world, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {} public void emitBlockQuads(BlockRenderView world, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
model_1.emitBlockQuads(world, state, pos, randomSupplier, context);
model_2.emitBlockQuads(world, state, pos, randomSupplier, context);
}
@Override // models are emitted here because no checks are done on items @Override // models are emitted here because no checks are done on items
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) { public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {

View File

@ -125,6 +125,7 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
@Override @Override
public void emitBlockQuads(BlockRenderView world, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) { public void emitBlockQuads(BlockRenderView world, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
BlockState theme = (world.getBlockEntity(pos) instanceof ThemeableBlockEntity s) ? s.getTheme(theme_index) : null; BlockState theme = (world.getBlockEntity(pos) instanceof ThemeableBlockEntity s) ? s.getTheme(theme_index) : null;
QuadEmitter quad_emitter = context.getEmitter(); QuadEmitter quad_emitter = context.getEmitter();
if(theme == null || theme.isAir()) { if(theme == null || theme.isAir()) {
getRetexturedMesh( getRetexturedMesh(

View File

@ -12,7 +12,6 @@ import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.renderer.v1.Renderer; import net.fabricmc.fabric.api.renderer.v1.Renderer;
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.util.function.BooleanBiFunction; import net.minecraft.util.function.BooleanBiFunction;
@ -52,8 +51,6 @@ public class RenderHelper {
Random random = Random.create(); Random random = Random.create();
List<List<QuadPosBounds>> model_bounds = models.stream() List<List<QuadPosBounds>> model_bounds = models.stream()
.map(ForwardingBakedModel::getWrappedModel)
.filter(Objects::nonNull)
.map(wrapped -> wrapped.getQuads(state, null, random)) .map(wrapped -> wrapped.getQuads(state, null, random))
.map(quads -> quads.stream().map(quad -> { .map(quads -> quads.stream().map(quad -> {
quad_emitter.fromVanilla(quad, material, null); quad_emitter.fromVanilla(quad, material, null);
@ -98,12 +95,17 @@ public class RenderHelper {
// Doing this method from scratch as it is simpler to do than injecting everywhere // Doing this method from scratch as it is simpler to do than injecting everywhere
public static boolean shouldDrawSide(BlockState self_state, BlockView world, BlockPos pos, Direction side, BlockPos other_pos, int theme_index) { public static boolean shouldDrawSide(BlockState self_state, BlockView world, BlockPos pos, Direction side, BlockPos other_pos, int theme_index) {
ThemeableBlockEntity self = world.getBlockEntity(pos) instanceof ThemeableBlockEntity e ? e : null;
ThemeableBlockEntity other = world.getBlockEntity(other_pos) instanceof ThemeableBlockEntity e ? e : null;
BlockState other_state = world.getBlockState(other_pos); BlockState other_state = world.getBlockState(other_pos);
ThemeableBlockEntity self = world.getBlockEntity(pos) instanceof ThemeableBlockEntity e
&& self_state.getBlock() instanceof ReFramedBlock
? e : null;
ThemeableBlockEntity other = world.getBlockEntity(other_pos) instanceof ThemeableBlockEntity e
&& other_state.getBlock() instanceof ReFramedBlock
? e : null;
// normal behaviour // normal behaviour
if (self == null && other == null) return Block.shouldDrawSide(self_state, world, pos, side, other_pos); if (theme_index == 0 || (self == null && other == null))
return Block.shouldDrawSide(self_state, world, pos, side, other_pos);
// self is a normal Block // self is a normal Block
if (self == null && other_state.getBlock() instanceof ReFramedBlock other_block) { if (self == null && other_state.getBlock() instanceof ReFramedBlock other_block) {

View File

@ -26,8 +26,10 @@ public class CompatMixinPlugin implements IMixinConfigPlugin {
CONDITIONS.put("fr.adrien1106.reframed.mixin.render.BlockRenderInfoMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1))); CONDITIONS.put("fr.adrien1106.reframed.mixin.render.BlockRenderInfoMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.render.AbstractBlockRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1))); CONDITIONS.put("fr.adrien1106.reframed.mixin.render.AbstractBlockRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumTerrainRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1))); CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumTerrainRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumTerrainBlockRenderInfoMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumAbstractBlockRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1))); CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumAbstractBlockRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumBlockRenderInfoMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumNonTerrainBlockRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.render.BlockRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.SodiumBlockOcclusionCacheMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(2))); CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.SodiumBlockOcclusionCacheMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(2)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityConnectionPredicateMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4))); CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityConnectionPredicateMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityCTMBakedModelMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4))); CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityCTMBakedModelMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4)));
@ -38,6 +40,7 @@ public class CompatMixinPlugin implements IMixinConfigPlugin {
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomClipboardMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5))); CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomClipboardMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomCloneBuilderToolMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5))); CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomCloneBuilderToolMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomPlacementMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5))); CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomPlacementMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomMappedBlockAndTintGetterMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomMoveBuilderToolMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5))); CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomMoveBuilderToolMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomScale3xMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5))); CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomScale3xMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5)));
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomRotSpriteMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5))); CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomRotSpriteMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5)));

View File

@ -1,5 +1,6 @@
package fr.adrien1106.reframed.mixin.compat; package fr.adrien1106.reframed.mixin.compat;
import com.llamalad7.mixinextras.sugar.Local;
import com.moulberry.axiom.render.regions.ChunkedBlockRegion; import com.moulberry.axiom.render.regions.ChunkedBlockRegion;
import com.moulberry.axiom.utils.IntMatrix; import com.moulberry.axiom.utils.IntMatrix;
import com.moulberry.axiom.world_modification.CompressedBlockEntity; import com.moulberry.axiom.world_modification.CompressedBlockEntity;
@ -9,29 +10,27 @@ import fr.adrien1106.reframed.util.mixin.IAxiomChunkedBlockRegionMixin;
import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin; import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin;
import fr.adrien1106.reframed.util.mixin.ThemedBlockEntity; import fr.adrien1106.reframed.util.mixin.ThemedBlockEntity;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntity;
import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.Camera; import net.minecraft.client.render.Camera;
import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.block.BlockRenderManager; import net.minecraft.client.render.block.BlockRenderManager;
import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtHelper;
import net.minecraft.registry.Registries;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.random.Random; import net.minecraft.util.math.random.Random;
import net.minecraft.world.BlockRenderView; import net.minecraft.world.BlockRenderView;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@ -43,11 +42,10 @@ import static fr.adrien1106.reframed.block.ReFramedEntity.BLOCKSTATE_KEY;
@Mixin(ChunkedBlockRegion.class) // TODO: Look here for better rotation/flip support @Mixin(ChunkedBlockRegion.class) // TODO: Look here for better rotation/flip support
public abstract class AxiomChunkedBlockRegionMixin implements IAxiomChunkedBlockRegionMixin { public abstract class AxiomChunkedBlockRegionMixin implements IAxiomChunkedBlockRegionMixin {
@Shadow
private static void renderBlock(BufferBuilder blockBuilder, BlockRenderManager renderManager, BlockPos.Mutable blockPos, Random rand, MatrixStack matrices, BlockRenderView blockAndTintGetter, Matrix4f currentPoseMatrix, Matrix4f basePoseMatrix, int x, int y, int z, BlockState dataState, boolean useAmbientOcclusion) {}
@Shadow public abstract BlockState getBlockState(BlockPos pos); @Shadow public abstract BlockState getBlockState(BlockPos pos);
@Shadow public abstract @Nullable BlockEntity getBlockEntity(BlockPos pos);
@Unique @Unique
private IntMatrix transform; private IntMatrix transform;
@Unique @Unique
@ -55,48 +53,46 @@ public abstract class AxiomChunkedBlockRegionMixin implements IAxiomChunkedBlock
@Unique @Unique
private Long2ObjectMap<CompressedBlockEntity> block_entities; private Long2ObjectMap<CompressedBlockEntity> block_entities;
@Unique
private static boolean isFrameModel(BakedModel model) {
return model instanceof RetexturingBakedModel || model instanceof MultiRetexturableModel;
}
@Redirect( @Unique
method = "uploadDirty", private static List<BakedModel> getModels(BakedModel model, BlockState state) {
if (isFrameModel(model))
return List.of(model);
else if (model instanceof IMultipartBakedModelMixin mpm)
return mpm.getModels(state).stream().filter(AxiomChunkedBlockRegionMixin::isFrameModel).toList();
else
return List.of();
}
@Inject(
method = "renderBlock",
at = @At( at = @At(
value = "INVOKE", value = "INVOKE_ASSIGN",
target = "Lcom/moulberry/axiom/render/regions/ChunkedBlockRegion;renderBlock(Lnet/minecraft/client/render/BufferBuilder;Lnet/minecraft/client/render/block/BlockRenderManager;Lnet/minecraft/util/math/BlockPos$Mutable;Lnet/minecraft/util/math/random/Random;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/world/BlockRenderView;Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;IIILnet/minecraft/block/BlockState;Z)V" target = "Lnet/minecraft/client/render/block/BlockRenderManager;getModel(Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/render/model/BakedModel;",
) shift = At.Shift.AFTER
) ),
private void onRenderBlock(BufferBuilder buffer, BlockRenderManager renderer, BlockPos.Mutable pos, Random rand, MatrixStack matrices, BlockRenderView world, Matrix4f current_pos, Matrix4f base_pos, int x, int y, int z, BlockState state, boolean use_ao) { cancellable = true)
BakedModel model; private static void onRenderBlock(BufferBuilder blockBuilder, BlockRenderManager renderer, BlockPos.Mutable pos, Random rand, MatrixStack matrices, BlockRenderView world, Matrix4f currentPoseMatrix, Matrix4f basePoseMatrix, int x, int y, int z, BlockState state, boolean useAmbientOcclusion, CallbackInfo ci, @Local BakedModel model) {
List<BakedModel> models; List<BakedModel> models;
if (block_entities != null if ((models = getModels(model, state)).isEmpty() // not a retexturable model
&& state.getRenderType() == BlockRenderType.MODEL || !(world.getBlockEntity(pos) instanceof ThemedBlockEntity block_entity) // not a themed block entity
&& (model = renderer.getModel(state)) != null ) return;
&& model instanceof IMultipartBakedModelMixin mpm
&& !(models = mpm.getModels(state) models.stream().flatMap(m -> m instanceof MultiRetexturableModel mm
.stream() ? mm.models().stream()
.filter(m -> m instanceof RetexturingBakedModel || m instanceof MultiRetexturableModel) : Stream.of((RetexturingBakedModel)m)
.toList()).isEmpty() ).forEach(m -> {
) { m.setCamo(world, block_entity.getTheme(m.getThemeIndex()), pos);
long key = BlockPos.asLong( if (useAmbientOcclusion && state.getLuminance() == 0 && m.useAmbientOcclusion()) renderer.getModelRenderer()
inverse_transform.transformX(pos.getX(), pos.getY(), pos.getZ()), .renderSmooth(world, m, state, pos, matrices, blockBuilder, true, rand, state.getRenderingSeed(pos), OverlayTexture.DEFAULT_UV);
inverse_transform.transformY(pos.getX(), pos.getY(), pos.getZ()), else renderer.getModelRenderer()
inverse_transform.transformZ(pos.getX(), pos.getY(), pos.getZ()) .renderFlat(world, m, state, pos, matrices, blockBuilder, true, rand, state.getRenderingSeed(pos), OverlayTexture.DEFAULT_UV);
); });
if (block_entities.containsKey(key)) { ci.cancel();
NbtCompound compound = block_entities.get(key).decompress();
models.stream()
.flatMap(m -> m instanceof MultiRetexturableModel mm
? mm.models().stream()
: Stream.of((RetexturingBakedModel)m)
)
.forEach(m -> m.setCamo(
world,
compound.contains(BLOCKSTATE_KEY + m.getThemeIndex())
? NbtHelper.toBlockState(Registries.BLOCK.getReadOnlyWrapper(), compound.getCompound(BLOCKSTATE_KEY + m.getThemeIndex()))
: null,
pos
));
}
}
renderBlock(buffer, renderer, pos, rand, matrices, world, current_pos, base_pos, x, y, z, state, use_ao);
} }
@Inject( @Inject(

View File

@ -0,0 +1,32 @@
package fr.adrien1106.reframed.mixin.compat;
import fr.adrien1106.reframed.block.ReFramedEntity;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(targets = "com.moulberry.axiom.render.ChunkRenderOverrider$MappedBlockAndTintGetter")
public class AxiomMappedBlockAndTintGetterMixin {
@Shadow @Final private World level;
@Inject(
method = "getBlockEntity",
at = @At(
value = "RETURN"
),
remap = false,
cancellable = true
)
private void onGetBlockEntity(BlockPos pos, CallbackInfoReturnable<BlockEntity> cir) {
if (!(level.getBlockEntity(pos) instanceof ReFramedEntity frame_entity)) return;
cir.setReturnValue(frame_entity);
}
}

View File

@ -0,0 +1,66 @@
package fr.adrien1106.reframed.mixin.compat;
import com.llamalad7.mixinextras.sugar.Local;
import fr.adrien1106.reframed.client.util.RenderHelper;
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
import link.infra.indium.renderer.render.BlockRenderInfo;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockRenderView;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(BlockRenderInfo.class)
public abstract class IndiumBlockRenderInfoMixin implements IBlockRenderInfoMixin {
@Shadow public abstract void prepareForBlock(BlockState blockState, BlockPos blockPos, long seed, boolean modelAo);
@Shadow public BlockPos blockPos;
@Shadow public BlockRenderView blockView;
@Shadow public BlockState blockState;
@Shadow(remap = false) private int cullResultFlags;
@Unique private int theme_index = 0;
@Unique private int model_hash = 0;
@Inject(
method = "shouldDrawFace",
at = @At(
value = "INVOKE",
target = "Llink/infra/indium/renderer/render/BlockRenderInfo;shouldDrawFaceInner(Lnet/minecraft/util/math/Direction;)Z"
),
cancellable = true
)
private void shouldDrawInnerFace(Direction face, CallbackInfoReturnable<Boolean> cir, @Local int mask) {
BlockPos other_pos = blockPos.offset(face);
if (!(blockView.getBlockEntity(blockPos) instanceof ThemeableBlockEntity
|| blockView.getBlockEntity(other_pos) instanceof ThemeableBlockEntity)
) return;
boolean result = RenderHelper.shouldDrawSide(blockState, blockView, blockPos, face, other_pos, theme_index);
if (result) cullResultFlags |= mask;
cir.setReturnValue(result);
}
@Override
public void prepareForBlock(BlockState blockState, BlockPos blockPos, long seed, boolean modelAo, int theme_index, int model_hash) {
this.theme_index = theme_index;
this.model_hash = model_hash;
prepareForBlock(blockState, blockPos, seed, modelAo);
}
@Override
public int getThemeIndex() {
return theme_index;
}
@Override
public int getModelHash() {
return model_hash;
}
}

View File

@ -0,0 +1,84 @@
package fr.adrien1106.reframed.mixin.compat;
import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
import fr.adrien1106.reframed.client.model.RetexturingBakedModel;
import fr.adrien1106.reframed.client.util.RenderHelper;
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin;
import link.infra.indium.renderer.aocalc.AoCalculator;
import link.infra.indium.renderer.render.AbstractBlockRenderContext;
import link.infra.indium.renderer.render.BlockRenderInfo;
import link.infra.indium.renderer.render.NonTerrainBlockRenderContext;
import link.infra.indium.renderer.render.SingleBlockLightDataCache;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.BlockRenderView;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
@Mixin(NonTerrainBlockRenderContext.class)
public abstract class IndiumNonTerrainBlockRenderContextMixin extends AbstractBlockRenderContext {
@Shadow(remap = false) @Final private SingleBlockLightDataCache lightCache;
@Shadow private VertexConsumer vertexConsumer;
@Inject(
method = "render",
at = @At(
value = "INVOKE",
target = "Llink/infra/indium/renderer/render/BlockRenderInfo;prepareForWorld(Lnet/minecraft/world/BlockRenderView;Z)V",
shift = At.Shift.AFTER
),
remap = false,
cancellable = true
)
private void renderMultipleModels(BlockRenderView blockView, BakedModel wrapper, BlockState state, BlockPos pos, MatrixStack matrixStack, VertexConsumer buffer, boolean cull, Random random, long seed, int overlay, CallbackInfo ci) {
if (!(wrapper instanceof IMultipartBakedModelMixin wrapped)) return;
List<BakedModel> models = wrapped.getModels(state);
if (models.stream().noneMatch(bakedModel ->
bakedModel instanceof MultiRetexturableModel
|| bakedModel instanceof RetexturingBakedModel
)) return;
models.forEach(model -> {
if (model instanceof MultiRetexturableModel multi_model) {
RenderHelper.computeInnerCull(state, multi_model.models(), model.hashCode());
multi_model.models().forEach(rexteruable_model ->
renderModel(state, pos, seed, rexteruable_model, aoCalc, blockInfo, this, model.hashCode())
);
} else if (model instanceof RetexturingBakedModel rexteruable_model)
renderModel(state, pos, seed, rexteruable_model, aoCalc, blockInfo, this, model.hashCode());
else model.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this);
});
blockInfo.release();
lightCache.release();
vertexConsumer = null;
ci.cancel();
}
@Unique
private static void renderModel(BlockState state, BlockPos pos, long seed, RetexturingBakedModel model, AoCalculator aoCalc, BlockRenderInfo block_info, RenderContext context, int model_hash) {
aoCalc.clear();
((IBlockRenderInfoMixin) block_info).prepareForBlock(
state, pos, seed,
model.useAmbientOcclusion(block_info.blockView, pos),
model.getThemeIndex(), model_hash
);
model.emitBlockQuads(block_info.blockView, block_info.blockState, block_info.blockPos, block_info.randomSupplier, context);
}
}

View File

@ -1,55 +0,0 @@
package fr.adrien1106.reframed.mixin.compat;
import fr.adrien1106.reframed.client.util.RenderHelper;
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
import link.infra.indium.renderer.render.BlockRenderInfo;
import link.infra.indium.renderer.render.TerrainBlockRenderInfo;
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockOcclusionCache;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView;
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;
@Mixin(TerrainBlockRenderInfo.class)
public abstract class IndiumTerrainBlockRenderInfoMixin extends BlockRenderInfo implements IBlockRenderInfoMixin {
@Unique private int theme_index = 0;
@Unique private int model_hash = 0;
@Redirect(
method = "shouldDrawFaceInner",
at = @At(
value = "INVOKE",
target = "Lme/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache;shouldDrawSide(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;)Z"
)
)
private boolean shouldDrawCamoSide(BlockOcclusionCache instance, BlockState state, BlockView view, BlockPos pos, Direction face) {
BlockPos other_pos = pos.offset(face);
if (!(view.getBlockEntity(pos) instanceof ThemeableBlockEntity
|| view.getBlockEntity(other_pos) instanceof ThemeableBlockEntity))
return instance.shouldDrawSide(state, view, pos, face);
return RenderHelper.shouldDrawSide(state, view, pos, face, other_pos, theme_index);
}
@Override
public void prepareForBlock(BlockState blockState, BlockPos blockPos, long seed, boolean modelAo, int theme_index, int model_hash) {
this.theme_index = theme_index;
this.model_hash = model_hash;
prepareForBlock(blockState, blockPos, seed, modelAo);
}
@Override
public int getThemeIndex() {
return theme_index;
}
@Override
public int getModelHash() {
return model_hash;
}
}

View File

@ -0,0 +1,40 @@
package fr.adrien1106.reframed.mixin.render;
import com.llamalad7.mixinextras.sugar.Local;
import fr.adrien1106.reframed.client.model.RetexturingBakedModel;
import fr.adrien1106.reframed.client.util.RenderHelper;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.block.BlockModelRenderer;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(BlockModelRenderer.class)
public class BlockModelRendererMixin {
@Redirect(
method = "renderSmooth",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/block/Block;shouldDrawSide(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;Lnet/minecraft/util/math/BlockPos;)Z"
)
)
private boolean shouldDrawFrameSideS(BlockState state, BlockView world, BlockPos pos, Direction side, BlockPos other_pos, @Local(argsOnly = true) BakedModel model) {
return RenderHelper.shouldDrawSide(state, world, pos, side, other_pos, model instanceof RetexturingBakedModel rm ? rm.getThemeIndex() : 0);
}
@Redirect(
method = "renderFlat",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/block/Block;shouldDrawSide(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;Lnet/minecraft/util/math/BlockPos;)Z"
)
)
private boolean shouldDrawFrameSideF(BlockState state, BlockView world, BlockPos pos, Direction side, BlockPos other_pos, @Local(argsOnly = true) BakedModel model) {
return RenderHelper.shouldDrawSide(state, world, pos, side, other_pos, model instanceof RetexturingBakedModel rm ? rm.getThemeIndex() : 0);
}
}

View File

@ -0,0 +1,78 @@
package fr.adrien1106.reframed.mixin.render;
import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
import fr.adrien1106.reframed.client.model.RetexturingBakedModel;
import fr.adrien1106.reframed.client.util.RenderHelper;
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.AoCalculator;
import net.fabricmc.fabric.impl.client.indigo.renderer.render.AbstractBlockRenderContext;
import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderContext;
import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderInfo;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.BlockRenderView;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
@Mixin(BlockRenderContext.class)
public abstract class BlockRenderContextMixin extends AbstractBlockRenderContext {
@Shadow private VertexConsumer vertexConsumer;
@Inject(
method = "render",
at = @At(
value = "INVOKE",
target = "Lnet/fabricmc/fabric/impl/client/indigo/renderer/render/BlockRenderInfo;prepareForWorld(Lnet/minecraft/world/BlockRenderView;Z)V",
shift = At.Shift.AFTER
),
cancellable = true
)
private void renderMultipleModels(BlockRenderView blockView, BakedModel wrapper, BlockState state, BlockPos pos, MatrixStack matrixStack, VertexConsumer buffer, boolean cull, Random random, long seed, int overlay, CallbackInfo ci) {
if (!(wrapper instanceof IMultipartBakedModelMixin wrapped)) return;
List<BakedModel> models = wrapped.getModels(state);
if (models.stream().noneMatch(bakedModel ->
bakedModel instanceof MultiRetexturableModel
|| bakedModel instanceof RetexturingBakedModel
)) return;
models.forEach(model -> {
if (model instanceof MultiRetexturableModel multi_model) {
RenderHelper.computeInnerCull(state, multi_model.models(), model.hashCode());
multi_model.models().forEach(rexteruable_model ->
renderModel(state, pos, rexteruable_model, aoCalc, blockInfo, this, model.hashCode())
);
} else if (model instanceof RetexturingBakedModel rexteruable_model)
renderModel(state, pos, rexteruable_model, aoCalc, blockInfo, this, model.hashCode());
else model.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this);
});
blockInfo.release();
vertexConsumer = null;
ci.cancel();
}
@Unique
private static void renderModel(BlockState state, BlockPos pos, RetexturingBakedModel model, AoCalculator aoCalc, BlockRenderInfo block_info, RenderContext context, int model_hash) {
aoCalc.clear();
((IBlockRenderInfoMixin) block_info).prepareForBlock(
state, pos,
model.useAmbientOcclusion(block_info.blockView, pos),
model.getThemeIndex(), model_hash
);
model.emitBlockQuads(block_info.blockView, block_info.blockState, block_info.blockPos, block_info.randomSupplier, context);
}
}

View File

@ -19,6 +19,7 @@
"compat.AxiomClientBlockEntitySerializerMixin", "compat.AxiomClientBlockEntitySerializerMixin",
"compat.AxiomClipboardMixin", "compat.AxiomClipboardMixin",
"compat.AxiomCloneBuilderToolMixin", "compat.AxiomCloneBuilderToolMixin",
"compat.AxiomMappedBlockAndTintGetterMixin",
"compat.AxiomMoveBuilderToolMixin", "compat.AxiomMoveBuilderToolMixin",
"compat.AxiomPlacementMixin", "compat.AxiomPlacementMixin",
"compat.AxiomRotSpriteMixin", "compat.AxiomRotSpriteMixin",
@ -28,7 +29,8 @@
"compat.ContinuityCTMQuadTransformMixin", "compat.ContinuityCTMQuadTransformMixin",
"compat.ContinuityModelWrappingHandlerMixin", "compat.ContinuityModelWrappingHandlerMixin",
"compat.IndiumAbstractBlockRenderContextMixin", "compat.IndiumAbstractBlockRenderContextMixin",
"compat.IndiumTerrainBlockRenderInfoMixin", "compat.IndiumBlockRenderInfoMixin",
"compat.IndiumNonTerrainBlockRenderContextMixin",
"compat.IndiumTerrainRenderContextMixin", "compat.IndiumTerrainRenderContextMixin",
"compat.SodiumBlockOcclusionCacheMixin", "compat.SodiumBlockOcclusionCacheMixin",
"model.WeightedBakedModelAccessor", "model.WeightedBakedModelAccessor",
@ -36,6 +38,8 @@
"particles.AccessorSpriteBillboardParticle", "particles.AccessorSpriteBillboardParticle",
"particles.MixinBlockDustParticle", "particles.MixinBlockDustParticle",
"render.AbstractBlockRenderContextMixin", "render.AbstractBlockRenderContextMixin",
"render.BlockModelRendererMixin",
"render.BlockRenderContextMixin",
"render.BlockRenderInfoMixin", "render.BlockRenderInfoMixin",
"render.MultipartBakedModelMixin", "render.MultipartBakedModelMixin",
"render.TerrainRenderContextMixin", "render.TerrainRenderContextMixin",