From 115aad3d40755e2e8d91dcc9647f3ae3f24b9b96 Mon Sep 17 00:00:00 2001 From: PepperCode1 <44146161+PepperCode1@users.noreply.github.com> Date: Thu, 29 Feb 2024 16:25:20 -0800 Subject: [PATCH] Multi-improvements - Make lib instance shaders multiply color value instead of overriding it - Improve MultiBlockModelBuilder - Accept an Iterable instead of a Collection and assume all block state data is already contained within the render world - Accept a Function instead of a Map as the model data lookup - Allow enabling fluid rendering (all rendered fluids are currently unshaded) - Refactor VirtualEmptyBlockGetter - Move elementary implementations into abstract VirtualBlockGetter class - Extract virtual LevelLightEngine into separate VirtualLightEngine class with ability to lookup light values per pos - Turn VirtualEmptyBlockGetter into a class and make all methods final to ensure instances of this class are actually empty even if subclassed - Make BakedModelBufferer class package private - Remove unused VertexTransformations class - Remove Experimental annotation from VisualizationContext.createEmbedding --- .../visualization/VisualizationContext.java | 3 - .../flywheel/lib/model/SingleMeshModel.java | 6 +- .../lib/model/baked/BakedModelBufferer.java | 123 +++++++++++------- .../lib/model/baked/BakedModelBuilder.java | 12 +- .../lib/model/baked/BlockModelBuilder.java | 12 +- .../model/baked/MultiBlockModelBuilder.java | 52 ++++---- .../baked/TransformingVertexConsumer.java | 88 +++++++++++++ .../lib/model/baked/VirtualBlockGetter.java | 43 ++++++ .../model/baked/VirtualEmptyBlockGetter.java | 122 +++-------------- .../lib/model/baked/VirtualLightEngine.java | 95 ++++++++++++++ .../lib/vertex/VertexTransformations.java | 44 ------- .../flywheel/flywheel/instance/oriented.vert | 2 +- .../flywheel/flywheel/instance/shadow.vert | 2 - .../flywheel/instance/transformed.vert | 2 +- 14 files changed, 361 insertions(+), 245 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/lib/model/baked/TransformingVertexConsumer.java create mode 100644 src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualBlockGetter.java create mode 100644 src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualLightEngine.java delete mode 100644 src/main/java/com/jozufozu/flywheel/lib/vertex/VertexTransformations.java diff --git a/src/main/java/com/jozufozu/flywheel/api/visualization/VisualizationContext.java b/src/main/java/com/jozufozu/flywheel/api/visualization/VisualizationContext.java index 88935dd13..ed112f50a 100644 --- a/src/main/java/com/jozufozu/flywheel/api/visualization/VisualizationContext.java +++ b/src/main/java/com/jozufozu/flywheel/api/visualization/VisualizationContext.java @@ -1,7 +1,5 @@ package com.jozufozu.flywheel.api.visualization; -import org.jetbrains.annotations.ApiStatus; - import com.jozufozu.flywheel.api.BackendImplemented; import com.jozufozu.flywheel.api.instance.InstancerProvider; @@ -24,6 +22,5 @@ public interface VisualizationContext { */ Vec3i renderOrigin(); - @ApiStatus.Experimental VisualEmbedding createEmbedding(); } diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/SingleMeshModel.java b/src/main/java/com/jozufozu/flywheel/lib/model/SingleMeshModel.java index ce38c6231..245eeaffc 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/SingleMeshModel.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/SingleMeshModel.java @@ -11,16 +11,16 @@ import com.jozufozu.flywheel.api.model.Model; public class SingleMeshModel implements Model { private final Mesh mesh; - private final Material material; + private final ImmutableList meshList; public SingleMeshModel(Mesh mesh, Material material) { this.mesh = mesh; - this.material = material; + meshList = ImmutableList.of(new ConfiguredMesh(material, mesh)); } @Override public List meshes() { - return ImmutableList.of(new ConfiguredMesh(material, mesh)); + return meshList; } @Override diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBufferer.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBufferer.java index cd3b5e37b..0820471d4 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBufferer.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBufferer.java @@ -1,7 +1,7 @@ package com.jozufozu.flywheel.lib.model.baked; -import java.util.Collection; -import java.util.Map; +import java.util.Iterator; +import java.util.function.Function; import org.jetbrains.annotations.Nullable; @@ -11,6 +11,7 @@ import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexFormat; +import net.minecraft.client.renderer.ItemBlockRenderTypes; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.BlockRenderDispatcher; import net.minecraft.client.renderer.block.ModelBlockRenderer; @@ -21,11 +22,11 @@ import net.minecraft.util.RandomSource; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.block.RenderShape; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; +import net.minecraft.world.level.material.FluidState; import net.minecraftforge.client.ChunkRenderTypeSet; import net.minecraftforge.client.model.data.ModelData; -public final class BakedModelBufferer { +final class BakedModelBufferer { private static final RenderType[] CHUNK_LAYERS = RenderType.chunkBufferLayers().toArray(RenderType[]::new); private static final int CHUNK_LAYER_AMOUNT = CHUNK_LAYERS.length; @@ -122,12 +123,13 @@ public final class BakedModelBufferer { bufferSingleShadeSeparated(renderDispatcher.getModelRenderer(), renderWorld, renderDispatcher.getBlockModel(state), state, poseStack, modelData, resultConsumer); } - public static void bufferMultiBlock(Collection blocks, BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, @Nullable PoseStack poseStack, Map modelDataMap, ResultConsumer resultConsumer) { + public static void bufferMultiBlock(BlockRenderDispatcher renderDispatcher, Iterator posIterator, BlockAndTintGetter renderWorld, @Nullable PoseStack poseStack, Function modelDataLookup, boolean renderFluids, ResultConsumer resultConsumer) { ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get(); if (poseStack == null) { poseStack = objects.identityPoseStack; } RandomSource random = objects.random; + TransformingVertexConsumer transformingWrapper = objects.transformingWrapper; BufferBuilder[] buffers = objects.shadedBuffers; for (BufferBuilder buffer : buffers) { @@ -137,35 +139,51 @@ public final class BakedModelBufferer { ModelBlockRenderer blockRenderer = renderDispatcher.getModelRenderer(); ModelBlockRenderer.enableCaching(); - for (StructureTemplate.StructureBlockInfo blockInfo : blocks) { - BlockState state = blockInfo.state(); + while (posIterator.hasNext()) { + BlockPos pos = posIterator.next(); + BlockState state = renderWorld.getBlockState(pos); - if (state.getRenderShape() != RenderShape.MODEL) { - continue; + if (renderFluids) { + FluidState fluidState = state.getFluidState(); + + if (!fluidState.isEmpty()) { + RenderType layer = ItemBlockRenderTypes.getRenderLayer(fluidState); + int layerIndex = layer.getChunkLayerId(); + + transformingWrapper.prepare(buffers[layerIndex], poseStack); + + poseStack.pushPose(); + poseStack.translate(pos.getX() - (pos.getX() & 0xF), pos.getY() - (pos.getY() & 0xF), pos.getZ() - (pos.getZ() & 0xF)); + renderDispatcher.renderLiquid(pos, renderWorld, transformingWrapper, state, fluidState); + poseStack.popPose(); + } } - BlockPos pos = blockInfo.pos(); - long seed = state.getSeed(pos); - BakedModel model = renderDispatcher.getBlockModel(state); - ModelData modelData = modelDataMap.getOrDefault(pos, ModelData.EMPTY); - modelData = model.getModelData(renderWorld, pos, state, modelData); - random.setSeed(seed); - ChunkRenderTypeSet renderTypes = model.getRenderTypes(state, random, modelData); + if (state.getRenderShape() == RenderShape.MODEL) { + long seed = state.getSeed(pos); + BakedModel model = renderDispatcher.getBlockModel(state); + ModelData modelData = modelDataLookup.apply(pos); + modelData = model.getModelData(renderWorld, pos, state, modelData); + random.setSeed(seed); + ChunkRenderTypeSet renderTypes = model.getRenderTypes(state, random, modelData); - for (RenderType renderType : renderTypes) { - int layerIndex = renderType.getChunkLayerId(); - - BufferBuilder buffer = buffers[layerIndex]; - - poseStack.pushPose(); - poseStack.translate(pos.getX(), pos.getY(), pos.getZ()); - blockRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, buffer, true, random, seed, OverlayTexture.NO_OVERLAY, modelData, renderType); - poseStack.popPose(); + for (RenderType renderType : renderTypes) { + int layerIndex = renderType.getChunkLayerId(); + + BufferBuilder buffer = buffers[layerIndex]; + + poseStack.pushPose(); + poseStack.translate(pos.getX(), pos.getY(), pos.getZ()); + blockRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, buffer, true, random, seed, OverlayTexture.NO_OVERLAY, modelData, renderType); + poseStack.popPose(); + } } } ModelBlockRenderer.clearCache(); + transformingWrapper.clear(); + for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) { RenderType renderType = CHUNK_LAYERS[layerIndex]; BufferBuilder buffer = buffers[layerIndex]; @@ -177,13 +195,14 @@ public final class BakedModelBufferer { } } - public static void bufferMultiBlockShadeSeparated(Collection blocks, BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, @Nullable PoseStack poseStack, Map modelDataMap, ShadeSeparatedResultConsumer resultConsumer) { + public static void bufferMultiBlockShadeSeparated(BlockRenderDispatcher renderDispatcher, Iterator posIterator, BlockAndTintGetter renderWorld, @Nullable PoseStack poseStack, Function modelDataLookup, boolean renderFluids, ShadeSeparatedResultConsumer resultConsumer) { ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get(); if (poseStack == null) { poseStack = objects.identityPoseStack; } RandomSource random = objects.random; ShadeSeparatingVertexConsumer shadeSeparatingWrapper = objects.shadeSeparatingWrapper; + TransformingVertexConsumer transformingWrapper = objects.transformingWrapper; BufferBuilder[] shadedBuffers = objects.shadedBuffers; BufferBuilder[] unshadedBuffers = objects.unshadedBuffers; @@ -197,36 +216,51 @@ public final class BakedModelBufferer { ModelBlockRenderer blockRenderer = renderDispatcher.getModelRenderer(); ModelBlockRenderer.enableCaching(); - for (StructureTemplate.StructureBlockInfo blockInfo : blocks) { - BlockState state = blockInfo.state(); + while (posIterator.hasNext()) { + BlockPos pos = posIterator.next(); + BlockState state = renderWorld.getBlockState(pos); - if (state.getRenderShape() != RenderShape.MODEL) { - continue; + if (renderFluids) { + FluidState fluidState = state.getFluidState(); + + if (!fluidState.isEmpty()) { + RenderType layer = ItemBlockRenderTypes.getRenderLayer(fluidState); + int layerIndex = layer.getChunkLayerId(); + + transformingWrapper.prepare(shadedBuffers[layerIndex], poseStack); + + poseStack.pushPose(); + poseStack.translate(pos.getX() - (pos.getX() & 0xF), pos.getY() - (pos.getY() & 0xF), pos.getZ() - (pos.getZ() & 0xF)); + renderDispatcher.renderLiquid(pos, renderWorld, transformingWrapper, state, fluidState); + poseStack.popPose(); + } } - BlockPos pos = blockInfo.pos(); - long seed = state.getSeed(pos); - BakedModel model = renderDispatcher.getBlockModel(state); - ModelData modelData = modelDataMap.getOrDefault(pos, ModelData.EMPTY); - modelData = model.getModelData(renderWorld, pos, state, modelData); - random.setSeed(seed); - ChunkRenderTypeSet renderTypes = model.getRenderTypes(state, random, modelData); + if (state.getRenderShape() == RenderShape.MODEL) { + long seed = state.getSeed(pos); + BakedModel model = renderDispatcher.getBlockModel(state); + ModelData modelData = modelDataLookup.apply(pos); + modelData = model.getModelData(renderWorld, pos, state, modelData); + random.setSeed(seed); + ChunkRenderTypeSet renderTypes = model.getRenderTypes(state, random, modelData); - for (RenderType renderType : renderTypes) { - int layerIndex = renderType.getChunkLayerId(); + for (RenderType renderType : renderTypes) { + int layerIndex = renderType.getChunkLayerId(); - shadeSeparatingWrapper.prepare(shadedBuffers[layerIndex], unshadedBuffers[layerIndex]); + shadeSeparatingWrapper.prepare(shadedBuffers[layerIndex], unshadedBuffers[layerIndex]); - poseStack.pushPose(); - poseStack.translate(pos.getX(), pos.getY(), pos.getZ()); - blockRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, shadeSeparatingWrapper, true, random, seed, OverlayTexture.NO_OVERLAY, modelData, renderType); - poseStack.popPose(); + poseStack.pushPose(); + poseStack.translate(pos.getX(), pos.getY(), pos.getZ()); + blockRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, shadeSeparatingWrapper, true, random, seed, OverlayTexture.NO_OVERLAY, modelData, renderType); + poseStack.popPose(); + } } } ModelBlockRenderer.clearCache(); shadeSeparatingWrapper.clear(); + transformingWrapper.clear(); for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) { RenderType renderType = CHUNK_LAYERS[layerIndex]; @@ -258,6 +292,7 @@ public final class BakedModelBufferer { public final RandomSource random = RandomSource.createNewThreadLocalInstance(); public final ShadeSeparatingVertexConsumer shadeSeparatingWrapper = new ShadeSeparatingVertexConsumer(); + public final TransformingVertexConsumer transformingWrapper = new TransformingVertexConsumer(); public final BufferBuilder[] shadedBuffers = new BufferBuilder[CHUNK_LAYER_AMOUNT]; public final BufferBuilder[] unshadedBuffers = new BufferBuilder[CHUNK_LAYER_AMOUNT]; diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBuilder.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBuilder.java index 65a7278e8..9847cf00e 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBuilder.java @@ -23,22 +23,17 @@ import net.minecraftforge.client.model.data.ModelData; public class BakedModelBuilder { private final BakedModel bakedModel; - private boolean shadeSeparated = true; private BlockAndTintGetter renderWorld; private BlockState blockState; private PoseStack poseStack; private ModelData modelData; + private boolean shadeSeparated = true; private BiFunction materialFunc; public BakedModelBuilder(BakedModel bakedModel) { this.bakedModel = bakedModel; } - public BakedModelBuilder disableShadeSeparation() { - shadeSeparated = false; - return this; - } - public BakedModelBuilder renderWorld(BlockAndTintGetter renderWorld) { this.renderWorld = renderWorld; return this; @@ -59,6 +54,11 @@ public class BakedModelBuilder { return this; } + public BakedModelBuilder disableShadeSeparation() { + shadeSeparated = false; + return this; + } + public BakedModelBuilder materialFunc(BiFunction materialFunc) { this.materialFunc = materialFunc; return this; diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/baked/BlockModelBuilder.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/BlockModelBuilder.java index 374313ef3..5a77226ec 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/baked/BlockModelBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/BlockModelBuilder.java @@ -21,21 +21,16 @@ import net.minecraftforge.client.model.data.ModelData; public class BlockModelBuilder { private final BlockState state; - private boolean shadeSeparated = true; private BlockAndTintGetter renderWorld; private PoseStack poseStack; private ModelData modelData; + private boolean shadeSeparated = true; private BiFunction materialFunc; public BlockModelBuilder(BlockState state) { this.state = state; } - public BlockModelBuilder disableShadeSeparation() { - shadeSeparated = false; - return this; - } - public BlockModelBuilder renderWorld(BlockAndTintGetter renderWorld) { this.renderWorld = renderWorld; return this; @@ -51,6 +46,11 @@ public class BlockModelBuilder { return this; } + public BlockModelBuilder disableShadeSeparation() { + shadeSeparated = false; + return this; + } + public BlockModelBuilder materialFunc(BiFunction materialFunc) { this.materialFunc = materialFunc; return this; diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/baked/MultiBlockModelBuilder.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/MultiBlockModelBuilder.java index d40e5ee08..f221b6a84 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/baked/MultiBlockModelBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/MultiBlockModelBuilder.java @@ -1,9 +1,7 @@ package com.jozufozu.flywheel.lib.model.baked; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; import java.util.function.BiFunction; +import java.util.function.Function; import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.api.material.Material; @@ -20,29 +18,20 @@ import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.renderer.RenderType; import net.minecraft.core.BlockPos; import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; import net.minecraftforge.client.model.data.ModelData; public class MultiBlockModelBuilder { - private final Collection blocks; - private boolean shadeSeparated = true; - private BlockAndTintGetter renderWorld; + private final BlockAndTintGetter renderWorld; + private final Iterable positions; private PoseStack poseStack; - private Map modelDataMap; + private Function modelDataLookup; + private boolean renderFluids = false; + private boolean shadeSeparated = true; private BiFunction materialFunc; - public MultiBlockModelBuilder(Collection blocks) { - this.blocks = blocks; - } - - public MultiBlockModelBuilder disableShadeSeparation() { - shadeSeparated = false; - return this; - } - - public MultiBlockModelBuilder renderWorld(BlockAndTintGetter renderWorld) { + public MultiBlockModelBuilder(BlockAndTintGetter renderWorld, Iterable positions) { this.renderWorld = renderWorld; - return this; + this.positions = positions; } public MultiBlockModelBuilder poseStack(PoseStack poseStack) { @@ -50,8 +39,18 @@ public class MultiBlockModelBuilder { return this; } - public MultiBlockModelBuilder modelDataMap(Map modelDataMap) { - this.modelDataMap = modelDataMap; + public MultiBlockModelBuilder modelDataLookup(Function modelDataLookup) { + this.modelDataLookup = modelDataLookup; + return this; + } + + public MultiBlockModelBuilder enableFluidRendering() { + renderFluids = true; + return this; + } + + public MultiBlockModelBuilder disableShadeSeparation() { + shadeSeparated = false; return this; } @@ -61,11 +60,8 @@ public class MultiBlockModelBuilder { } public TessellatedModel build() { - if (renderWorld == null) { - renderWorld = VirtualEmptyBlockGetter.INSTANCE; - } - if (modelDataMap == null) { - modelDataMap = Collections.emptyMap(); + if (modelDataLookup == null) { + modelDataLookup = pos -> ModelData.EMPTY; } if (materialFunc == null) { materialFunc = ModelUtil::getMaterial; @@ -83,7 +79,7 @@ public class MultiBlockModelBuilder { out.add(new Model.ConfiguredMesh(material, mesh)); } }; - BakedModelBufferer.bufferMultiBlockShadeSeparated(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, modelDataMap, resultConsumer); + BakedModelBufferer.bufferMultiBlockShadeSeparated(ModelUtil.VANILLA_RENDERER, positions.iterator(), renderWorld, poseStack, modelDataLookup, renderFluids, resultConsumer); } else { ResultConsumer resultConsumer = (renderType, data) -> { Material material = materialFunc.apply(renderType, true); @@ -94,7 +90,7 @@ public class MultiBlockModelBuilder { out.add(new Model.ConfiguredMesh(material, mesh)); } }; - BakedModelBufferer.bufferMultiBlock(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, modelDataMap, resultConsumer); + BakedModelBufferer.bufferMultiBlock(ModelUtil.VANILLA_RENDERER, positions.iterator(), renderWorld, poseStack, modelDataLookup, renderFluids, resultConsumer); } return new TessellatedModel(out.build(), shadeSeparated); diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/baked/TransformingVertexConsumer.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/TransformingVertexConsumer.java new file mode 100644 index 000000000..09054e2b4 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/TransformingVertexConsumer.java @@ -0,0 +1,88 @@ +package com.jozufozu.flywheel.lib.model.baked; + +import org.joml.Matrix3f; +import org.joml.Matrix4f; + +import com.jozufozu.flywheel.lib.math.MatrixMath; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; + +class TransformingVertexConsumer implements VertexConsumer { + private VertexConsumer delegate; + private PoseStack poseStack; + + public void prepare(VertexConsumer delegate, PoseStack poseStack) { + this.delegate = delegate; + this.poseStack = poseStack; + } + + public void clear() { + delegate = null; + poseStack = null; + } + + @Override + public VertexConsumer vertex(double x, double y, double z) { + Matrix4f matrix = poseStack.last().pose(); + float fx = (float) x; + float fy = (float) y; + float fz = (float) z; + delegate.vertex( + MatrixMath.transformPositionX(matrix, fx, fy, fz), + MatrixMath.transformPositionY(matrix, fx, fy, fz), + MatrixMath.transformPositionZ(matrix, fx, fy, fz)); + return this; + } + + @Override + public VertexConsumer color(int red, int green, int blue, int alpha) { + delegate.color(red, green, blue, alpha); + return this; + } + + @Override + public VertexConsumer uv(float u, float v) { + delegate.uv(u, v); + return this; + } + + @Override + public VertexConsumer overlayCoords(int u, int v) { + delegate.overlayCoords(u, v); + return this; + } + + @Override + public VertexConsumer uv2(int u, int v) { + delegate.uv2(u, v); + return this; + } + + @Override + public VertexConsumer normal(float x, float y, float z) { + Matrix3f matrix = poseStack.last().normal(); + float fx = (float) x; + float fy = (float) y; + float fz = (float) z; + delegate.normal( + MatrixMath.transformNormalX(matrix, fx, fy, fz), + MatrixMath.transformNormalY(matrix, fx, fy, fz), + MatrixMath.transformNormalZ(matrix, fx, fy, fz)); + return this; + } + + @Override + public void endVertex() { + delegate.endVertex(); + } + + @Override + public void defaultColor(int red, int green, int blue, int alpha) { + delegate.defaultColor(red, green, blue, alpha); + } + + @Override + public void unsetDefaultColor() { + delegate.unsetDefaultColor(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualBlockGetter.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualBlockGetter.java new file mode 100644 index 000000000..773eb1d6b --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualBlockGetter.java @@ -0,0 +1,43 @@ +package com.jozufozu.flywheel.lib.model.baked; + +import java.util.function.ToIntFunction; + +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.registries.Registries; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.ColorResolver; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.material.FluidState; + +public abstract class VirtualBlockGetter implements BlockAndTintGetter { + protected final VirtualLightEngine lightEngine; + + public VirtualBlockGetter(ToIntFunction blockLightFunc, ToIntFunction skyLightFunc) { + lightEngine = new VirtualLightEngine(blockLightFunc, skyLightFunc, this); + } + + @Override + public FluidState getFluidState(BlockPos pos) { + return getBlockState(pos).getFluidState(); + } + + @Override + public float getShade(Direction direction, boolean shaded) { + return 1f; + } + + @Override + public LevelLightEngine getLightEngine() { + return lightEngine; + } + + @Override + public int getBlockTint(BlockPos pos, ColorResolver resolver) { + Biome plainsBiome = Minecraft.getInstance().getConnection().registryAccess().registryOrThrow(Registries.BIOME).getOrThrow(Biomes.PLAINS); + return resolver.getColor(plainsBiome, pos.getX(), pos.getZ()); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualEmptyBlockGetter.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualEmptyBlockGetter.java index 9d5f7c29c..c860e1acb 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualEmptyBlockGetter.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualEmptyBlockGetter.java @@ -1,34 +1,25 @@ package com.jozufozu.flywheel.lib.model.baked; +import java.util.function.ToIntFunction; + import org.jetbrains.annotations.Nullable; -import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.SectionPos; -import net.minecraft.core.registries.Registries; import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.ColorResolver; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.LightChunk; -import net.minecraft.world.level.chunk.LightChunkGetter; -import net.minecraft.world.level.lighting.LayerLightEventListener; -import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.Fluids; -public interface VirtualEmptyBlockGetter extends BlockAndTintGetter { - public static final VirtualEmptyBlockGetter INSTANCE = new StaticLightImpl(0, 15); - public static final VirtualEmptyBlockGetter FULL_BRIGHT = new StaticLightImpl(15, 15); - public static final VirtualEmptyBlockGetter FULL_DARK = new StaticLightImpl(0, 0); +public class VirtualEmptyBlockGetter extends VirtualBlockGetter { + public static final VirtualEmptyBlockGetter INSTANCE = new VirtualEmptyBlockGetter(p -> 0, p -> 15); + public static final VirtualEmptyBlockGetter FULL_BRIGHT = new VirtualEmptyBlockGetter(p -> 15, p -> 15); + public static final VirtualEmptyBlockGetter FULL_DARK = new VirtualEmptyBlockGetter(p -> 0, p -> 0); + + public VirtualEmptyBlockGetter(ToIntFunction blockLightFunc, ToIntFunction skyLightFunc) { + super(blockLightFunc, skyLightFunc); + } public static boolean is(BlockAndTintGetter blockGetter) { return blockGetter instanceof VirtualEmptyBlockGetter; @@ -36,110 +27,27 @@ public interface VirtualEmptyBlockGetter extends BlockAndTintGetter { @Override @Nullable - default BlockEntity getBlockEntity(BlockPos pos) { + public final BlockEntity getBlockEntity(BlockPos pos) { return null; } @Override - default BlockState getBlockState(BlockPos pos) { + public final BlockState getBlockState(BlockPos pos) { return Blocks.AIR.defaultBlockState(); } @Override - default FluidState getFluidState(BlockPos pos) { + public final FluidState getFluidState(BlockPos pos) { return Fluids.EMPTY.defaultFluidState(); } @Override - default int getHeight() { + public final int getHeight() { return 1; } @Override - default int getMinBuildHeight() { + public final int getMinBuildHeight() { return 0; } - - @Override - default float getShade(Direction direction, boolean shaded) { - return 1f; - } - - @Override - default int getBlockTint(BlockPos pos, ColorResolver resolver) { - Biome plainsBiome = Minecraft.getInstance().getConnection().registryAccess().registryOrThrow(Registries.BIOME).getOrThrow(Biomes.PLAINS); - return resolver.getColor(plainsBiome, pos.getX(), pos.getZ()); - } - - public static class StaticLightImpl implements VirtualEmptyBlockGetter { - private final LevelLightEngine lightEngine; - - public StaticLightImpl(int blockLight, int skyLight) { - lightEngine = new LevelLightEngine(new LightChunkGetter() { - @Override - @Nullable - public LightChunk getChunkForLighting(int x, int z) { - return null; - } - - @Override - public BlockGetter getLevel() { - return StaticLightImpl.this; - } - }, false, false) { - private final LayerLightEventListener blockListener = createStaticListener(blockLight); - private final LayerLightEventListener skyListener = createStaticListener(skyLight); - - @Override - public LayerLightEventListener getLayerListener(LightLayer layer) { - return layer == LightLayer.BLOCK ? blockListener : skyListener; - } - }; - } - - private static LayerLightEventListener createStaticListener(int light) { - return new LayerLightEventListener() { - @Override - public void checkBlock(BlockPos pos) { - } - - @Override - public boolean hasLightWork() { - return false; - } - - @Override - public int runLightUpdates() { - return 0; - } - - @Override - public void updateSectionStatus(SectionPos pos, boolean isSectionEmpty) { - } - - @Override - public void setLightEnabled(ChunkPos pos, boolean lightEnabled) { - } - - @Override - public void propagateLightSources(ChunkPos pos) { - } - - @Override - public DataLayer getDataLayerData(SectionPos pos) { - return null; - } - - @Override - public int getLightValue(BlockPos pos) { - return light; - } - }; - } - - @Override - public LevelLightEngine getLightEngine() { - return lightEngine; - } - } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualLightEngine.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualLightEngine.java new file mode 100644 index 000000000..33710ce99 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualLightEngine.java @@ -0,0 +1,95 @@ +package com.jozufozu.flywheel.lib.model.baked; + +import java.util.function.ToIntFunction; + +import org.jetbrains.annotations.Nullable; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.LightChunk; +import net.minecraft.world.level.chunk.LightChunkGetter; +import net.minecraft.world.level.lighting.LayerLightEventListener; +import net.minecraft.world.level.lighting.LevelLightEngine; + +public final class VirtualLightEngine extends LevelLightEngine { + private final LayerLightEventListener blockListener; + private final LayerLightEventListener skyListener; + + public VirtualLightEngine(ToIntFunction blockLightFunc, ToIntFunction skyLightFunc, BlockGetter level) { + super(new LightChunkGetter() { + @Override + @Nullable + public LightChunk getChunkForLighting(int x, int z) { + return null; + } + + @Override + public BlockGetter getLevel() { + return level; + } + }, false, false); + + blockListener = new VirtualLayerLightEventListener(blockLightFunc); + skyListener = new VirtualLayerLightEventListener(skyLightFunc); + } + + @Override + public LayerLightEventListener getLayerListener(LightLayer layer) { + return layer == LightLayer.BLOCK ? blockListener : skyListener; + } + + @Override + public int getRawBrightness(BlockPos pos, int amount) { + int i = skyListener.getLightValue(pos) - amount; + int j = blockListener.getLightValue(pos); + return Math.max(j, i); + } + + private static class VirtualLayerLightEventListener implements LayerLightEventListener { + private final ToIntFunction lightFunc; + + public VirtualLayerLightEventListener(ToIntFunction lightFunc) { + this.lightFunc = lightFunc; + } + + @Override + public void checkBlock(BlockPos pos) { + } + + @Override + public boolean hasLightWork() { + return false; + } + + @Override + public int runLightUpdates() { + return 0; + } + + @Override + public void updateSectionStatus(SectionPos pos, boolean isSectionEmpty) { + } + + @Override + public void setLightEnabled(ChunkPos pos, boolean lightEnabled) { + } + + @Override + public void propagateLightSources(ChunkPos pos) { + } + + @Override + public DataLayer getDataLayerData(SectionPos pos) { + return null; + } + + @Override + public int getLightValue(BlockPos pos) { + return lightFunc.applyAsInt(pos); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/lib/vertex/VertexTransformations.java b/src/main/java/com/jozufozu/flywheel/lib/vertex/VertexTransformations.java deleted file mode 100644 index 285f951fe..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/vertex/VertexTransformations.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.jozufozu.flywheel.lib.vertex; - -import org.joml.Matrix3f; -import org.joml.Matrix4f; - -import com.jozufozu.flywheel.api.vertex.MutableVertexList; -import com.jozufozu.flywheel.lib.math.MatrixMath; - -public final class VertexTransformations { - private VertexTransformations() { - } - - public static void transformPos(MutableVertexList vertexList, int index, Matrix4f matrix) { - float x = vertexList.x(index); - float y = vertexList.y(index); - float z = vertexList.z(index); - vertexList.x(index, MatrixMath.transformPositionX(matrix, x, y, z)); - vertexList.y(index, MatrixMath.transformPositionY(matrix, x, y, z)); - vertexList.z(index, MatrixMath.transformPositionZ(matrix, x, y, z)); - } - - /** - * Assumes the matrix preserves scale. - */ - public static void transformNormal(MutableVertexList vertexList, int index, Matrix3f matrix) { - float nx = vertexList.normalX(index); - float ny = vertexList.normalY(index); - float nz = vertexList.normalZ(index); - float tnx = MatrixMath.transformNormalX(matrix, nx, ny, nz); - float tny = MatrixMath.transformNormalY(matrix, nx, ny, nz); - float tnz = MatrixMath.transformNormalZ(matrix, nx, ny, nz); - // seems to be the case that sqrLength is always ~1.0 - // float sqrLength = fma(tnx, tnx, fma(tny, tny, tnz * tnz)); - // if (sqrLength != 0) { - // float f = invsqrt(sqrLength); - // tnx *= f; - // tny *= f; - // tnz *= f; - // } - vertexList.normalX(index, tnx); - vertexList.normalY(index, tny); - vertexList.normalZ(index, tnz); - } -} diff --git a/src/main/resources/assets/flywheel/flywheel/instance/oriented.vert b/src/main/resources/assets/flywheel/flywheel/instance/oriented.vert index dc77d53d9..5e79d8f9b 100644 --- a/src/main/resources/assets/flywheel/flywheel/instance/oriented.vert +++ b/src/main/resources/assets/flywheel/flywheel/instance/oriented.vert @@ -3,7 +3,7 @@ void flw_instanceVertex(in FlwInstance i) { flw_vertexPos = vec4(rotateByQuaternion(flw_vertexPos.xyz - i.pivot, i.rotation) + i.pivot + i.position, 1.0); flw_vertexNormal = rotateByQuaternion(flw_vertexNormal, i.rotation); - flw_vertexColor = i.color; + flw_vertexColor *= i.color; flw_vertexOverlay = i.overlay; flw_vertexLight = i.light / 15.; } diff --git a/src/main/resources/assets/flywheel/flywheel/instance/shadow.vert b/src/main/resources/assets/flywheel/flywheel/instance/shadow.vert index f3d3c8c5f..97649f624 100644 --- a/src/main/resources/assets/flywheel/flywheel/instance/shadow.vert +++ b/src/main/resources/assets/flywheel/flywheel/instance/shadow.vert @@ -7,6 +7,4 @@ void flw_instanceVertex(in FlwInstance i) { flw_vertexTexCoord = (flw_vertexPos.xz - i.entityPosXZ) * 0.5 / i.radius + 0.5; flw_vertexColor.a = i.alpha; - // no overlay - flw_vertexOverlay = ivec2(0, 10); } diff --git a/src/main/resources/assets/flywheel/flywheel/instance/transformed.vert b/src/main/resources/assets/flywheel/flywheel/instance/transformed.vert index 2bf7de822..e56b1b640 100644 --- a/src/main/resources/assets/flywheel/flywheel/instance/transformed.vert +++ b/src/main/resources/assets/flywheel/flywheel/instance/transformed.vert @@ -1,7 +1,7 @@ void flw_instanceVertex(in FlwInstance i) { flw_vertexPos = i.pose * flw_vertexPos; flw_vertexNormal = i.normal * flw_vertexNormal; - flw_vertexColor = i.color; + flw_vertexColor *= i.color; flw_vertexOverlay = i.overlay; flw_vertexLight = i.light / 15.; }