v1.5 new shapes + self culling + caching + coding tools/cleanup #10

Merged
Adrien1106 merged 11 commits from dev into master 2024-03-14 22:30:30 +01:00
15 changed files with 188 additions and 33 deletions
Showing only changes of commit e6c9ee63cd - Show all commits

View File

@ -76,4 +76,15 @@ public record QuadPosBounds(float min_x, float max_x, float min_y, float max_y,
quad.pos(i, pos); quad.pos(i, pos);
} }
} }
@Override
public boolean equals(Object obj) {
if (!(obj instanceof QuadPosBounds other)) return false;
return MathHelper.approximatelyEquals(min_x, other.min_x)
&& MathHelper.approximatelyEquals(min_y, other.min_y)
&& MathHelper.approximatelyEquals(min_z, other.min_z)
&& MathHelper.approximatelyEquals(max_x, other.max_x)
&& MathHelper.approximatelyEquals(max_y, other.max_y)
&& MathHelper.approximatelyEquals(max_z, other.max_z);
}
} }

View File

@ -9,10 +9,7 @@ import fr.adrien1106.reframed.client.model.apperance.CamoAppearanceManager;
import fr.adrien1106.reframed.client.model.apperance.WeightedComputedAppearance; import fr.adrien1106.reframed.client.model.apperance.WeightedComputedAppearance;
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; import net.fabricmc.fabric.api.renderer.v1.mesh.*;
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.renderer.v1.model.ForwardingBakedModel; import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
@ -27,6 +24,7 @@ import net.minecraft.util.math.Direction;
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 java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier; import java.util.function.Supplier;
public abstract class RetexturingBakedModel extends ForwardingBakedModel { public abstract class RetexturingBakedModel extends ForwardingBakedModel {
@ -167,12 +165,15 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
MeshBuilder builder = ReFramedClient.HELPER.getFabricRenderer().meshBuilder(); MeshBuilder builder = ReFramedClient.HELPER.getFabricRenderer().meshBuilder();
QuadEmitter emitter = builder.getEmitter(); QuadEmitter emitter = builder.getEmitter();
AtomicInteger quad_index = new AtomicInteger();
getBaseMesh(key.state_key, state).forEach(quad -> { getBaseMesh(key.state_key, state).forEach(quad -> {
int i = -1; int i = -1;
do { do {
emitter.copyFrom(quad); emitter.copyFrom(quad);
i = key.appearance.transformQuad(emitter, i, key.model_id, ao, uv_lock); i = key.appearance.transformQuad(emitter, i, quad_index.get(), key.model_id, ao, uv_lock);
} while (i > 0); } while (i > 0);
// kinda weird to do it like that but other directions don't use the quad_index so it doesn't matter
if (quad.cullFace() == null) quad_index.getAndIncrement();
}); });
return builder.build(); return builder.build();
@ -191,9 +192,10 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
@Override @Override
public boolean transform(MutableQuadView quad) { public boolean transform(MutableQuadView quad) {
if(quad.tag() == 0) return true; int camo_quad_index = quad.tag() - ((quad.tag() >>> 8) << 8);
if(camo_quad_index == 0) return true;
if(appearance.hasColor(quad.nominalFace(), model_id, quad.tag())) quad.color(tint, tint, tint, tint); if(appearance.hasColor(quad.nominalFace(), model_id, camo_quad_index)) quad.color(tint, tint, tint, tint);
return true; return true;
} }

View File

@ -28,7 +28,7 @@ public abstract class CamoAppearance {
return ao && ao_material != null? ao_material : material; return ao && ao_material != null? ao_material : material;
} }
public int transformQuad(QuadEmitter quad, int i, int model_id, boolean ao, boolean uv_lock) { public int transformQuad(QuadEmitter quad, int i, int quad_index, int model_id, boolean ao, boolean uv_lock) {
if(quad.tag() == 0) return 0; // Pass the quad through unmodified. if(quad.tag() == 0) return 0; // Pass the quad through unmodified.
Direction direction = quad.nominalFace(); Direction direction = quad.nominalFace();
@ -36,6 +36,7 @@ public abstract class CamoAppearance {
if (i == -1) i = sprites.size(); if (i == -1) i = sprites.size();
SpriteProperties properties = sprites.get(sprites.size() - i); SpriteProperties properties = sprites.get(sprites.size() - i);
int tag = i + (quad_index << 8);
i--; i--;
QuadPosBounds bounds = properties.bounds(); QuadPosBounds bounds = properties.bounds();
@ -47,7 +48,7 @@ public abstract class CamoAppearance {
| properties.flags() | properties.flags()
| (uv_lock ? MutableQuadView.BAKE_LOCK_UV : 0) | (uv_lock ? MutableQuadView.BAKE_LOCK_UV : 0)
); );
quad.tag(i+1); quad.tag(tag);
quad.emit(); quad.emit();
return i; return i;
} }
@ -64,7 +65,7 @@ public abstract class CamoAppearance {
MutableQuadView.BAKE_NORMALIZED MutableQuadView.BAKE_NORMALIZED
| MutableQuadView.BAKE_LOCK_UV | MutableQuadView.BAKE_LOCK_UV
); );
quad.tag(i+1); quad.tag(tag);
quad.emit(); quad.emit();
return i; return i;
} }

View File

@ -11,9 +11,7 @@ import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtHelper; import net.minecraft.nbt.NbtHelper;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; 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.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

View File

@ -21,9 +21,11 @@ public class CompatMixinPlugin implements IMixinConfigPlugin {
"fr.adrien1106.reframed.mixin.compat.AthenaBakedModelMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(0)), "fr.adrien1106.reframed.mixin.compat.AthenaBakedModelMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(0)),
"fr.adrien1106.reframed.mixin.compat.AthenaWrappedGetterMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(0)), "fr.adrien1106.reframed.mixin.compat.AthenaWrappedGetterMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(0)),
"fr.adrien1106.reframed.mixin.render.TerrainRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)), "fr.adrien1106.reframed.mixin.render.TerrainRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)),
"fr.adrien1106.reframed.mixin.compat.IndiumTerrainRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)),
"fr.adrien1106.reframed.mixin.render.BlockRenderInfoMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)), "fr.adrien1106.reframed.mixin.render.BlockRenderInfoMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)),
"fr.adrien1106.reframed.mixin.render.AbstractBlockRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)),
"fr.adrien1106.reframed.mixin.compat.IndiumTerrainRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)),
"fr.adrien1106.reframed.mixin.compat.IndiumTerrainBlockRenderInfoMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)), "fr.adrien1106.reframed.mixin.compat.IndiumTerrainBlockRenderInfoMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)),
"fr.adrien1106.reframed.mixin.compat.IndiumAbstractBlockRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)),
"fr.adrien1106.reframed.mixin.compat.SodiumBlockOcclusionCacheMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(2)) "fr.adrien1106.reframed.mixin.compat.SodiumBlockOcclusionCacheMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(2))
); );

View File

@ -0,0 +1,29 @@
package fr.adrien1106.reframed.mixin.compat;
import com.llamalad7.mixinextras.sugar.Local;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
import link.infra.indium.renderer.mesh.MutableQuadViewImpl;
import link.infra.indium.renderer.render.AbstractBlockRenderContext;
import link.infra.indium.renderer.render.BlockRenderInfo;
import net.minecraft.util.math.Direction;
import org.jetbrains.annotations.Nullable;
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.Redirect;
@Mixin(AbstractBlockRenderContext.class)
public abstract class IndiumAbstractBlockRenderContextMixin {
@Shadow(remap = false) protected BlockRenderInfo blockInfo;
@Shadow public abstract boolean isFaceCulled(@Nullable Direction face);
@Redirect(method = "renderQuad", at = @At(value = "INVOKE", target = "Llink/infra/indium/renderer/render/AbstractBlockRenderContext;isFaceCulled(Lnet/minecraft/util/math/Direction;)Z"))
private boolean shouldDrawInnerQuad(AbstractBlockRenderContext instance, Direction face, @Local(argsOnly = true) MutableQuadViewImpl quad) {
if (face != null || quad.tag() == 0 || !(blockInfo instanceof IBlockRenderInfoMixin info) || info.getThemeIndex() == 0) return isFaceCulled(face);
return !BlockHelper.shouldDrawInnerFace(blockInfo.blockState, blockInfo.blockView, blockInfo.blockPos, quad.tag() >>> 8, info.getThemeIndex());
}
}

View File

@ -18,7 +18,7 @@ import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(TerrainBlockRenderInfo.class) @Mixin(TerrainBlockRenderInfo.class)
public abstract class IndiumTerrainBlockRenderInfoMixin extends BlockRenderInfo implements IBlockRenderInfoMixin { public abstract class IndiumTerrainBlockRenderInfoMixin extends BlockRenderInfo implements IBlockRenderInfoMixin {
@Unique private int theme_index = 1; @Unique private int theme_index = 0;
@Redirect( @Redirect(
method = "shouldDrawFaceInner", method = "shouldDrawFaceInner",
@ -40,4 +40,9 @@ public abstract class IndiumTerrainBlockRenderInfoMixin extends BlockRenderInfo
this.theme_index = theme_index; this.theme_index = theme_index;
prepareForBlock(blockState, blockPos, seed, modelAo); prepareForBlock(blockState, blockPos, seed, modelAo);
} }
@Override
public int getThemeIndex() {
return theme_index;
}
} }

View File

@ -1,6 +1,7 @@
package fr.adrien1106.reframed.mixin.compat; package fr.adrien1106.reframed.mixin.compat;
import fr.adrien1106.reframed.client.model.MultiRetexturableModel; import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin; import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin; import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin;
import link.infra.indium.renderer.render.AbstractBlockRenderContext; import link.infra.indium.renderer.render.AbstractBlockRenderContext;
@ -31,6 +32,7 @@ public abstract class IndiumTerrainRenderContextMixin extends AbstractBlockRende
|| !(wrapped.getModel(ctx.state()) instanceof MultiRetexturableModel retexturing_model)) return; || !(wrapped.getModel(ctx.state()) instanceof MultiRetexturableModel retexturing_model)) return;
List<ForwardingBakedModel> models = retexturing_model.models(); List<ForwardingBakedModel> models = retexturing_model.models();
BlockHelper.computeInnerCull(ctx.state(), models);
int i = 0; int i = 0;
for (BakedModel model : models) { for (BakedModel model : models) {
i++; i++;

View File

@ -0,0 +1,36 @@
package fr.adrien1106.reframed.mixin.render;
import com.llamalad7.mixinextras.sugar.Local;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl;
import net.fabricmc.fabric.impl.client.indigo.renderer.render.AbstractBlockRenderContext;
import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderInfo;
import net.minecraft.util.math.Direction;
import org.jetbrains.annotations.Nullable;
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.Redirect;
@Mixin(AbstractBlockRenderContext.class)
public abstract class AbstractBlockRenderContextMixin {
@Shadow public abstract boolean isFaceCulled(@Nullable Direction face);
@Shadow(remap = false) @Final protected BlockRenderInfo blockInfo;
@Redirect(
method = "renderQuad",
at = @At(
value = "INVOKE",
target = "Lnet/fabricmc/fabric/impl/client/indigo/renderer/render/AbstractBlockRenderContext;isFaceCulled(Lnet/minecraft/util/math/Direction;)Z"
)
)
private boolean shouldDrawInnerQuad(AbstractBlockRenderContext instance, Direction face, @Local(argsOnly = true) MutableQuadViewImpl quad) {
if (face != null || quad.tag() == 0 || !(blockInfo instanceof IBlockRenderInfoMixin info) || info.getThemeIndex() == 0) return isFaceCulled(face);
return !BlockHelper.shouldDrawInnerFace(blockInfo.blockState, blockInfo.blockView, blockInfo.blockPos, quad.tag() >>> 8, info.getThemeIndex());
}
}

View File

@ -24,8 +24,7 @@ public abstract class BlockRenderInfoMixin implements IBlockRenderInfoMixin {
@Shadow public abstract void prepareForBlock(BlockState blockState, BlockPos blockPos, boolean modelAo); @Shadow public abstract void prepareForBlock(BlockState blockState, BlockPos blockPos, boolean modelAo);
@Shadow public BlockRenderView blockView; @Shadow public BlockRenderView blockView;
@Unique @Unique private int theme_index = 0;
private int theme_index = 1;
@ModifyArg(method = "prepareForBlock", @ModifyArg(method = "prepareForBlock",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/RenderLayers;" + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/RenderLayers;" +
@ -47,4 +46,9 @@ public abstract class BlockRenderInfoMixin implements IBlockRenderInfoMixin {
this.theme_index = theme_index; this.theme_index = theme_index;
prepareForBlock(state, pos, ao); prepareForBlock(state, pos, ao);
} }
@Override
public int getThemeIndex() {
return theme_index;
}
} }

View File

@ -1,6 +1,7 @@
package fr.adrien1106.reframed.mixin.render; package fr.adrien1106.reframed.mixin.render;
import fr.adrien1106.reframed.client.model.MultiRetexturableModel; import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
import fr.adrien1106.reframed.util.blocks.BlockHelper;
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin; import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin; import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin;
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
@ -30,10 +31,7 @@ public abstract class TerrainRenderContextMixin extends AbstractBlockRenderConte
|| !(wrapped.getModel(state) instanceof MultiRetexturableModel retexturing_model)) return; || !(wrapped.getModel(state) instanceof MultiRetexturableModel retexturing_model)) return;
List<ForwardingBakedModel> models = retexturing_model.models(); List<ForwardingBakedModel> models = retexturing_model.models();
// models.forEach(model -> // TODO self culling here BlockHelper.computeInnerCull(state, models);
// model.getWrappedModel().getQuads(state_key, null, blockInfo.randomSupplier.get())
// .forEach(quad -> QuadPosBounds.read(getEmitter().fromVanilla(quad.getVertexData(), 0)).min_x())
// );
int i = 0; int i = 0;
for (BakedModel model : models) { for (BakedModel model : models) {
i++; i++;

View File

@ -1,8 +1,15 @@
package fr.adrien1106.reframed.util.blocks; package fr.adrien1106.reframed.util.blocks;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import fr.adrien1106.reframed.block.ReFramedBlock; import fr.adrien1106.reframed.block.ReFramedBlock;
import fr.adrien1106.reframed.block.ReFramedEntity; import fr.adrien1106.reframed.block.ReFramedEntity;
import it.unimi.dsi.fastutil.objects.Object2ByteLinkedOpenHashMap; import fr.adrien1106.reframed.client.ReFramedClient;
import fr.adrien1106.reframed.client.model.QuadPosBounds;
import net.fabricmc.fabric.api.renderer.v1.Renderer;
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.model.ForwardingBakedModel;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.BlockEntityProvider;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
@ -18,14 +25,17 @@ import net.minecraft.util.hit.BlockHitResult;
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.shape.VoxelShape; import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes; import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockRenderView;
import net.minecraft.world.BlockView; import net.minecraft.world.BlockView;
import net.minecraft.world.World; import net.minecraft.world.World;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -36,17 +46,10 @@ import static net.minecraft.util.shape.VoxelShapes.combine;
public class BlockHelper { public class BlockHelper {
// self culling cache TODO move // self culling cache of the models not made thread local so that it is only computed once
private static final ThreadLocal<Object2ByteLinkedOpenHashMap<CullElement>> INNER_FACE_CULL_MAP = ThreadLocal.withInitial(() -> { private static final Cache<CullElement, Integer[]> INNER_CULL_MAP = CacheBuilder.newBuilder().maximumSize(1024).concurrencyLevel().build();
Object2ByteLinkedOpenHashMap<CullElement> object2ByteLinkedOpenHashMap = new Object2ByteLinkedOpenHashMap<>(2048, 0.25F) {
protected void rehash(int newN) {
}
};
object2ByteLinkedOpenHashMap.defaultReturnValue((byte)0);
return object2ByteLinkedOpenHashMap;
});
private record CullElement(BlockState state, int model, Direction side) {} private record CullElement(Object state_key, int model) {}
public static Corner getPlacementCorner(ItemPlacementContext ctx) { public static Corner getPlacementCorner(ItemPlacementContext ctx) {
Direction side = ctx.getSide().getOpposite(); Direction side = ctx.getSide().getOpposite();
@ -69,7 +72,7 @@ public class BlockHelper {
Math.abs(axis_1.choose(pos.x, pos.y, pos.z)) > Math.abs(axis_2.choose(pos.x, pos.y, pos.z)) Math.abs(axis_1.choose(pos.x, pos.y, pos.z)) > Math.abs(axis_2.choose(pos.x, pos.y, pos.z))
? axis_1 ? axis_1
: axis_2 : axis_2
).get(); ).orElse(null);
} }
public static Vec3d getRelativePos(Vec3d pos, BlockPos block_pos) { public static Vec3d getRelativePos(Vec3d pos, BlockPos block_pos) {
@ -216,6 +219,66 @@ public class BlockHelper {
return ActionResult.PASS; return ActionResult.PASS;
} }
/**
* compute which quad might cull with another model quad
* @param state - the state of the model
* @param models - list of models on the same block
*/
public static void computeInnerCull(BlockState state, List<ForwardingBakedModel> models) {
if (!(state.getBlock() instanceof ReFramedBlock frame_block)) return;
Object key = frame_block.getModelCacheKey(state);
if (INNER_CULL_MAP.asMap().containsKey(new CullElement(key, 1))) return;
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
QuadEmitter quad_emitter = r.meshBuilder().getEmitter();
RenderMaterial material = r.materialFinder().clear().find();
Random random = Random.create();
List<List<QuadPosBounds>> model_bounds = models.stream()
.map(ForwardingBakedModel::getWrappedModel)
.filter(Objects::nonNull)
.map(wrapped -> wrapped.getQuads(state, null, random))
.map(quads -> quads.stream().map(quad -> {
quad_emitter.fromVanilla(quad, material, null);
return QuadPosBounds.read(quad_emitter, false);
}).toList()).toList();
Integer[] cull_array;
for(int self_id = 1; self_id <= model_bounds.size(); self_id++) {
List<QuadPosBounds> self_bounds = model_bounds.get(self_id - 1);
cull_array = new Integer[self_bounds.size()];
for (int self_quad = 0; self_quad < cull_array.length; self_quad++) {
QuadPosBounds self_bound = self_bounds.get(self_quad);
for(int other_id = 1; other_id <= model_bounds.size(); other_id++) {
if (other_id == self_id) continue;
if (model_bounds.get(other_id - 1).stream().anyMatch(other_bound -> other_bound.equals(self_bound))) {
cull_array[self_quad] = other_id;
break;
}
}
}
INNER_CULL_MAP.put(new CullElement(key, self_id), cull_array);
}
}
public static boolean shouldDrawInnerFace(BlockState state, BlockRenderView view, BlockPos pos, int quad_index, int theme_index) {
if ( !(state.getBlock() instanceof ReFramedBlock frame_block)
|| !(view.getBlockEntity(pos) instanceof ThemeableBlockEntity frame_entity)
) return true;
CullElement key = new CullElement(frame_block.getModelCacheKey(state), theme_index);
if (!INNER_CULL_MAP.asMap().containsKey(key)) return true;
// needs to be Integer object because array is initialized with null not 0
Integer cull_theme = Objects.requireNonNull(INNER_CULL_MAP.getIfPresent(key))[quad_index];
if (cull_theme == null) return true; // no culling possible
BlockState self_theme = frame_entity.getTheme(theme_index);
BlockState other_theme = frame_entity.getTheme(cull_theme);
if (self_theme.isSideInvisible(other_theme, null)) return false;
return !self_theme.isOpaque() || !other_theme.isOpaque();
}
// 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 self = world.getBlockEntity(pos) instanceof ThemeableBlockEntity e ? e : null;

View File

@ -8,4 +8,6 @@ public interface IBlockRenderInfoMixin {
void prepareForBlock(BlockState state, BlockPos pos, boolean ao, int theme_index); void prepareForBlock(BlockState state, BlockPos pos, boolean ao, int theme_index);
void prepareForBlock(BlockState state, BlockPos pos, long seed, boolean ao, int theme_index); void prepareForBlock(BlockState state, BlockPos pos, long seed, boolean ao, int theme_index);
int getThemeIndex();
} }

View File

@ -30,7 +30,7 @@
"fabricloader": "^${loader_version}", "fabricloader": "^${loader_version}",
"fabric-api": "*" "fabric-api": "*"
}, },
"suggest": { "suggests": {
"athena": "^${athena_version}", "athena": "^${athena_version}",
"sodium": "^${sodium_version}", "sodium": "^${sodium_version}",
"indium": "^${indium_version}" "indium": "^${indium_version}"

View File

@ -14,6 +14,7 @@
"compat.AthenaBakedModelMixin", "compat.AthenaBakedModelMixin",
"compat.AthenaConnectedBlockModelMixin", "compat.AthenaConnectedBlockModelMixin",
"compat.AthenaWrappedGetterMixin", "compat.AthenaWrappedGetterMixin",
"compat.IndiumAbstractBlockRenderContextMixin",
"compat.IndiumTerrainBlockRenderInfoMixin", "compat.IndiumTerrainBlockRenderInfoMixin",
"compat.IndiumTerrainRenderContextMixin", "compat.IndiumTerrainRenderContextMixin",
"compat.SodiumBlockOcclusionCacheMixin", "compat.SodiumBlockOcclusionCacheMixin",
@ -21,6 +22,7 @@
"particles.AccessorParticle", "particles.AccessorParticle",
"particles.AccessorSpriteBillboardParticle", "particles.AccessorSpriteBillboardParticle",
"particles.MixinBlockDustParticle", "particles.MixinBlockDustParticle",
"render.AbstractBlockRenderContextMixin",
"render.BlockRenderInfoMixin", "render.BlockRenderInfoMixin",
"render.MultipartBakedModelMixin", "render.MultipartBakedModelMixin",
"render.TerrainRenderContextMixin", "render.TerrainRenderContextMixin",