diff --git a/src/main/java/com/jozufozu/flywheel/api/vertex/ShadedVertexList.java b/src/main/java/com/jozufozu/flywheel/api/vertex/ShadedVertexList.java new file mode 100644 index 000000000..227879b3a --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/vertex/ShadedVertexList.java @@ -0,0 +1,5 @@ +package com.jozufozu.flywheel.api.vertex; + +public interface ShadedVertexList extends VertexList { + boolean isShaded(int index); +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java index 73ea3e1c5..bd85a26b8 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedMaterialGroup.java @@ -44,7 +44,7 @@ public class InstancedMaterialGroup

implements MaterialG .onAMDWindows()) { this.allocator = FallbackAllocator.INSTANCE; } else { - this.allocator = new ModelPool(Formats.POS_TEX_NORMAL, 2048); + this.allocator = new ModelPool(Formats.POS_TEX_NORMAL); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/BufferBuilderExtension.java b/src/main/java/com/jozufozu/flywheel/backend/model/BufferBuilderExtension.java index 87d840792..4aec62268 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/model/BufferBuilderExtension.java +++ b/src/main/java/com/jozufozu/flywheel/backend/model/BufferBuilderExtension.java @@ -12,6 +12,8 @@ import com.mojang.blaze3d.vertex.VertexFormat; */ public interface BufferBuilderExtension { + int flywheel$getVertices(); + /** * Frees the internal ByteBuffer, if it exists. */ @@ -24,4 +26,12 @@ public interface BufferBuilderExtension { * @param vertexCount The number of vertices in the buffer. */ void flywheel$injectForRender(ByteBuffer buffer, VertexFormat format, int vertexCount); + + /** + * Appends the remaining bytes from the given buffer to this BufferBuilder. + * @param buffer The buffer from which to copy bytes. + * @throws IllegalStateException If this BufferBuilder is not started or is the process of writing a vertex + * @throws IllegalArgumentException If the given buffer does not contain a whole number of vertices + */ + void flywheel$appendBufferUnsafe(ByteBuffer buffer); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/ModelPool.java b/src/main/java/com/jozufozu/flywheel/backend/model/ModelPool.java index 7e50a5ddc..5c1d426c7 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/model/ModelPool.java +++ b/src/main/java/com/jozufozu/flywheel/backend/model/ModelPool.java @@ -35,16 +35,14 @@ public class ModelPool implements ModelAllocator { * Create a new model pool. * * @param vertexType The vertex type of the models that will be stored in the pool. - * @param initialSize The initial size of the pool, in vertices. */ - public ModelPool(VertexType vertexType, int initialSize) { + public ModelPool(VertexType vertexType) { this.vertexType = vertexType; int stride = vertexType.getStride(); vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER); vbo.bind(); - vbo.ensureCapacity((long) stride * initialSize); vbo.setGrowthMargin(stride * 64); } diff --git a/src/main/java/com/jozufozu/flywheel/core/Templates.java b/src/main/java/com/jozufozu/flywheel/core/Templates.java index 59b538a2f..30987940b 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Templates.java +++ b/src/main/java/com/jozufozu/flywheel/core/Templates.java @@ -1,13 +1,18 @@ package com.jozufozu.flywheel.core; +import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.backend.gl.GLSLVersion; import com.jozufozu.flywheel.core.compile.FragmentTemplateData; import com.jozufozu.flywheel.core.compile.InstancingTemplateData; import com.jozufozu.flywheel.core.compile.OneShotTemplateData; import com.jozufozu.flywheel.core.compile.Template; +import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.core.source.Resolver; public class Templates { + public static final FileResolution DIFFUSE_FILE = Resolver.INSTANCE.get(Flywheel.rl("core/diffuse.glsl")); + public static final Template INSTANCING = new Template<>(GLSLVersion.V330, InstancingTemplateData::new); public static final Template ONE_SHOT = new Template<>(GLSLVersion.V150, OneShotTemplateData::new); public static final Template FRAGMENT = new Template<>(GLSLVersion.V150, FragmentTemplateData::new); diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java index 6487c45c4..08e63a93b 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java @@ -5,6 +5,7 @@ import java.util.Objects; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.gl.shader.GlShader; import com.jozufozu.flywheel.backend.gl.shader.ShaderType; +import com.jozufozu.flywheel.core.Templates; import com.jozufozu.flywheel.core.shader.StateSnapshot; import com.jozufozu.flywheel.core.source.FileIndexImpl; import com.jozufozu.flywheel.core.source.FileResolution; @@ -40,6 +41,7 @@ public class VertexCompiler extends Memoizer { FileIndexImpl index = new FileIndexImpl(); + Templates.DIFFUSE_FILE.getFile().generateFinalSource(index, finalSource); header.getFile().generateFinalSource(index, finalSource); key.file.generateFinalSource(index, finalSource); diff --git a/src/main/java/com/jozufozu/flywheel/core/model/Model.java b/src/main/java/com/jozufozu/flywheel/core/model/Model.java index 6d1c2c0c5..eacfd3394 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/Model.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/Model.java @@ -16,7 +16,7 @@ import com.jozufozu.flywheel.core.QuadConverter; *

* *
{@code
- * IModel model = ...;
+ * Model model = ...;
  * VecBuffer into = ...;
  *
  * int initial = VecBuffer.unwrap().position();
diff --git a/src/main/java/com/jozufozu/flywheel/core/model/ModelTransformer.java b/src/main/java/com/jozufozu/flywheel/core/model/ModelTransformer.java
index 10eafd1c4..52e542ec7 100644
--- a/src/main/java/com/jozufozu/flywheel/core/model/ModelTransformer.java
+++ b/src/main/java/com/jozufozu/flywheel/core/model/ModelTransformer.java
@@ -1,5 +1,8 @@
 package com.jozufozu.flywheel.core.model;
 
+import java.util.function.IntPredicate;
+
+import com.jozufozu.flywheel.api.vertex.ShadedVertexList;
 import com.jozufozu.flywheel.api.vertex.VertexList;
 import com.jozufozu.flywheel.util.DiffuseLightCalculator;
 import com.jozufozu.flywheel.util.transform.Transform;
@@ -19,12 +22,18 @@ public class ModelTransformer {
 
 	private final Model model;
 	private final VertexList reader;
+	private final IntPredicate shadedPredicate;
 
 	public final Context context = new Context();
 
 	public ModelTransformer(Model model) {
 		this.model = model;
 		reader = model.getReader();
+		if (reader instanceof ShadedVertexList shaded) {
+			shadedPredicate = shaded::isShaded;
+		} else {
+			shadedPredicate = index -> true;
+		}
 	}
 
 	public void renderInto(Params params, PoseStack input, VertexConsumer builder) {
@@ -82,7 +91,7 @@ public class ModelTransformer {
 				a = reader.getA(i);
 			}
 			if (context.outputColorDiffuse) {
-				float instanceDiffuse = diffuseCalculator.getDiffuse(nx, ny, nz);
+				float instanceDiffuse = diffuseCalculator.getDiffuse(nx, ny, nz, shadedPredicate.test(i));
 				int colorR = transformColor(r, instanceDiffuse);
 				int colorG = transformColor(g, instanceDiffuse);
 				int colorB = transformColor(b, instanceDiffuse);
diff --git a/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java b/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java
index 9e711d61a..34c2e05e1 100644
--- a/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java
+++ b/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java
@@ -30,25 +30,53 @@ import net.minecraft.world.level.block.state.BlockState;
 import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
 
 public class ModelUtil {
-	public static BufferBuilder getBufferBuilder(BakedModel model, BlockState referenceState, PoseStack ms) {
+
+	private static final ThreadLocal THREAD_LOCAL_OBJECTS = ThreadLocal.withInitial(ThreadLocalObjects::new);
+
+	public static ShadeSeparatedBufferBuilder getBufferBuilder(BakedModel model, BlockState referenceState, PoseStack poseStack) {
+		return getBufferBuilder(VirtualEmptyBlockGetter.INSTANCE, model, referenceState, poseStack);
+	}
+
+	public static ShadeSeparatedBufferBuilder getBufferBuilder(BlockAndTintGetter renderWorld, BakedModel model, BlockState referenceState, PoseStack poseStack) {
 		ModelBlockRenderer blockRenderer = Minecraft.getInstance().getBlockRenderer().getModelRenderer();
-		BufferBuilder builder = new BufferBuilder(512);
+		ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
+
+		ShadeSeparatingVertexConsumer shadeSeparatingWrapper = objects.shadeSeparatingWrapper;
+		ShadeSeparatedBufferBuilder builder = new ShadeSeparatedBufferBuilder(512);
+		BufferBuilder unshadedBuilder = objects.unshadedBuilder;
+
 		builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
+		unshadedBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
+		shadeSeparatingWrapper.prepare(builder, unshadedBuilder);
 		model = DefaultLayerFilteringBakedModel.wrap(model);
-		blockRenderer.tesselateBlock(VirtualEmptyBlockGetter.INSTANCE, model, referenceState, BlockPos.ZERO, ms, builder,
-				false, new Random(), 42, OverlayTexture.NO_OVERLAY);
+		model = shadeSeparatingWrapper.wrapModel(model);
+		blockRenderer.tesselateBlock(renderWorld, model, referenceState, BlockPos.ZERO, poseStack, shadeSeparatingWrapper,
+				false, objects.random, 42, OverlayTexture.NO_OVERLAY);
+		shadeSeparatingWrapper.clear();
+		unshadedBuilder.end();
+		builder.appendUnshadedVertices(unshadedBuilder);
 		builder.end();
+
 		return builder;
 	}
 
-	public static BufferBuilder getBufferBuilderFromTemplate(BlockAndTintGetter renderWorld, RenderType layer, Collection blocks) {
-		BlockRenderDispatcher dispatcher = Minecraft.getInstance().getBlockRenderer();
-		ModelBlockRenderer modelRenderer = dispatcher.getModelRenderer();
+	public static ShadeSeparatedBufferBuilder getBufferBuilderFromTemplate(BlockAndTintGetter renderWorld, RenderType layer, Collection blocks) {
+		return getBufferBuilderFromTemplate(renderWorld, layer, blocks, new PoseStack());
+	}
+
+	public static ShadeSeparatedBufferBuilder getBufferBuilderFromTemplate(BlockAndTintGetter renderWorld, RenderType layer, Collection blocks, PoseStack poseStack) {
+		BlockRenderDispatcher dispatcher = Minecraft.getInstance().getBlockRenderer();	
+		ModelBlockRenderer modelRenderer = dispatcher.getModelRenderer();
+		ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
+
+		Random random = objects.random;
+		ShadeSeparatingVertexConsumer shadeSeparatingWrapper = objects.shadeSeparatingWrapper;
+		ShadeSeparatedBufferBuilder builder = new ShadeSeparatedBufferBuilder(512);
+		BufferBuilder unshadedBuilder = objects.unshadedBuilder;
 
-		PoseStack ms = new PoseStack();
-		Random random = new Random();
-		BufferBuilder builder = new BufferBuilder(512);
 		builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
+		unshadedBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
+		shadeSeparatingWrapper.prepare(builder, unshadedBuilder);
 
 		ModelBlockRenderer.enableCaching();
 		for (StructureTemplate.StructureBlockInfo info : blocks) {
@@ -65,19 +93,24 @@ public class ModelUtil {
 			} else {
 				model = CullingBakedModel.wrap(model);
 				model = LayerFilteringBakedModel.wrap(model, layer);
+				model = shadeSeparatingWrapper.wrapModel(model);
 			}
 
 			BlockPos pos = info.pos;
 
-			ms.pushPose();
-			ms.translate(pos.getX(), pos.getY(), pos.getZ());
-			modelRenderer.tesselateBlock(renderWorld, model, state, pos, ms, builder,
+			poseStack.pushPose();
+			poseStack.translate(pos.getX(), pos.getY(), pos.getZ());
+			modelRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, shadeSeparatingWrapper,
 					true, random, 42, OverlayTexture.NO_OVERLAY);
-			ms.popPose();
+			poseStack.popPose();
 		}
 		ModelBlockRenderer.clearCache();
 
+		shadeSeparatingWrapper.clear();
+		unshadedBuilder.end();
+		builder.appendUnshadedVertices(unshadedBuilder);
 		builder.end();
+
 		return builder;
 	}
 
@@ -91,4 +124,10 @@ public class ModelUtil {
 			return stack;
 		};
 	}
+
+	private static class ThreadLocalObjects {
+		public final Random random = new Random();
+		public final ShadeSeparatingVertexConsumer shadeSeparatingWrapper = new ShadeSeparatingVertexConsumer();
+		public final BufferBuilder unshadedBuilder = new BufferBuilder(512);
+	}
 }
diff --git a/src/main/java/com/jozufozu/flywheel/core/model/ShadeSeparatedBufferBuilder.java b/src/main/java/com/jozufozu/flywheel/core/model/ShadeSeparatedBufferBuilder.java
new file mode 100644
index 000000000..e7ca9f064
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/core/model/ShadeSeparatedBufferBuilder.java
@@ -0,0 +1,28 @@
+package com.jozufozu.flywheel.core.model;
+
+import java.nio.ByteBuffer;
+
+import com.jozufozu.flywheel.backend.model.BufferBuilderExtension;
+import com.jozufozu.flywheel.fabric.helper.BufferBuilderHelper;
+import com.mojang.blaze3d.vertex.BufferBuilder;
+import com.mojang.datafixers.util.Pair;
+
+public class ShadeSeparatedBufferBuilder extends BufferBuilder {
+	protected int unshadedStartVertex;
+
+	public ShadeSeparatedBufferBuilder(int capacity) {
+		super(capacity);
+	}
+
+	public void appendUnshadedVertices(BufferBuilder unshadedBuilder) {
+		Pair data = unshadedBuilder.popNextBuffer();
+		ByteBuffer buffer = data.getSecond();
+		BufferBuilderHelper.fixByteOrder(unshadedBuilder, buffer);
+		unshadedStartVertex = ((BufferBuilderExtension) this).flywheel$getVertices();
+		((BufferBuilderExtension) this).flywheel$appendBufferUnsafe(buffer);
+	}
+
+	public int getUnshadedStartVertex() {
+		return unshadedStartVertex;
+	}
+}
diff --git a/src/main/java/com/jozufozu/flywheel/core/model/ShadeSeparatingVertexConsumer.java b/src/main/java/com/jozufozu/flywheel/core/model/ShadeSeparatingVertexConsumer.java
new file mode 100644
index 000000000..307ffbbd3
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/core/model/ShadeSeparatingVertexConsumer.java
@@ -0,0 +1,122 @@
+package com.jozufozu.flywheel.core.model;
+
+import java.util.Random;
+import java.util.function.Supplier;
+
+import com.jozufozu.flywheel.fabric.model.FabricModelUtil;
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.blaze3d.vertex.VertexConsumer;
+
+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.QuadTransform;
+import net.minecraft.client.renderer.block.model.BakedQuad;
+import net.minecraft.client.resources.model.BakedModel;
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.BlockAndTintGetter;
+import net.minecraft.world.level.block.state.BlockState;
+
+public class ShadeSeparatingVertexConsumer implements VertexConsumer {
+	private final ShadeSeparatingBakedModel modelWrapper = new ShadeSeparatingBakedModel();
+	protected VertexConsumer shadedConsumer;
+	protected VertexConsumer unshadedConsumer;
+	protected VertexConsumer activeConsumer;
+
+	public void prepare(VertexConsumer shadedConsumer, VertexConsumer unshadedConsumer) {
+		this.shadedConsumer = shadedConsumer;
+		this.unshadedConsumer = unshadedConsumer;
+	}
+
+	public void clear() {
+		shadedConsumer = null;
+		unshadedConsumer = null;
+		activeConsumer = null;
+	}
+
+	public BakedModel wrapModel(BakedModel model) {
+		modelWrapper.setWrapped(model);
+		return modelWrapper;
+	}
+
+	protected void setActiveConsumer(boolean shaded) {
+		activeConsumer = shaded ? shadedConsumer : unshadedConsumer;
+	}
+
+	@Override
+	public void putBulkData(PoseStack.Pose poseEntry, BakedQuad quad, float[] colorMuls, float red, float green, float blue, int[] combinedLights, int combinedOverlay, boolean mulColor) {
+		if (quad.isShade()) {
+			shadedConsumer.putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor);
+		} else {
+			unshadedConsumer.putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor);
+		}
+	}
+
+	@Override
+	public VertexConsumer vertex(double x, double y, double z) {
+		activeConsumer.vertex(x, y, z);
+		return this;
+	}
+
+	@Override
+	public VertexConsumer color(int red, int green, int blue, int alpha) {
+		activeConsumer.color(red, green, blue, alpha);
+		return this;
+	}
+
+	@Override
+	public VertexConsumer uv(float u, float v) {
+		activeConsumer.uv(u, v);
+		return this;
+	}
+
+	@Override
+	public VertexConsumer overlayCoords(int u, int v) {
+		activeConsumer.overlayCoords(u, v);
+		return this;
+	}
+
+	@Override
+	public VertexConsumer uv2(int u, int v) {
+		activeConsumer.uv2(u, v);
+		return this;
+	}
+
+	@Override
+	public VertexConsumer normal(float x, float y, float z) {
+		activeConsumer.normal(x, y, z);
+		return this;
+	}
+
+	@Override
+	public void endVertex() {
+		activeConsumer.endVertex();
+	}
+
+	@Override
+	public void defaultColor(int red, int green, int blue, int alpha) {
+		activeConsumer.defaultColor(red, green, blue, alpha);
+	}
+
+	@Override
+	public void unsetDefaultColor() {
+		activeConsumer.unsetDefaultColor();
+	}
+
+	private class ShadeSeparatingBakedModel extends ForwardingBakedModel {
+		private final QuadTransform quadTransform = quad -> {
+			ShadeSeparatingVertexConsumer.this.setActiveConsumer(FabricModelUtil.isShaded(quad));
+			return true;
+		};
+
+		private void setWrapped(BakedModel model) {
+			wrapped = model;
+		}
+
+		@Override
+		public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) {
+			context.pushTransform(quadTransform);
+			super.emitBlockQuads(blockView, state, pos, randomSupplier, context);
+			context.popTransform();
+		}
+	}
+}
diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java
index ddf552509..ff218762a 100644
--- a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java
+++ b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java
@@ -6,6 +6,7 @@ import com.jozufozu.flywheel.api.vertex.VertexList;
 import com.jozufozu.flywheel.api.vertex.VertexType;
 import com.jozufozu.flywheel.core.layout.BufferLayout;
 import com.jozufozu.flywheel.core.layout.CommonItems;
+import com.jozufozu.flywheel.core.model.ShadeSeparatedBufferBuilder;
 import com.jozufozu.flywheel.fabric.helper.BufferBuilderHelper;
 import com.mojang.blaze3d.vertex.BufferBuilder;
 import com.mojang.blaze3d.vertex.DefaultVertexFormat;
@@ -58,6 +59,10 @@ Vertex FLWCreateVertex() {
 				""";
 	}
 
+	public BlockVertexListUnsafe.Shaded createReader(ByteBuffer buffer, int vertexCount, int unshadedStartVertex) {
+		return new BlockVertexListUnsafe.Shaded(buffer, vertexCount, unshadedStartVertex);
+	}
+
 	public VertexList createReader(BufferBuilder bufferBuilder) {
 		// TODO: try to avoid virtual model rendering
 		Pair pair = bufferBuilder.popNextBuffer();
@@ -69,6 +74,10 @@ Vertex FLWCreateVertex() {
 
 		ByteBuffer buffer = pair.getSecond();
 		BufferBuilderHelper.fixByteOrder(bufferBuilder, buffer);
-		return new BlockVertexListUnsafe(buffer, drawState.vertexCount());
+		if (bufferBuilder instanceof ShadeSeparatedBufferBuilder separated) {
+			return createReader(buffer, drawState.vertexCount(), separated.getUnshadedStartVertex());
+		} else {
+			return createReader(buffer, drawState.vertexCount());
+		}
 	}
 }
diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexList.java b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexList.java
index d12281dbf..57e0d0c25 100644
--- a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexList.java
+++ b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexList.java
@@ -2,7 +2,9 @@ package com.jozufozu.flywheel.core.vertex;
 
 import java.nio.ByteBuffer;
 
+import com.jozufozu.flywheel.api.vertex.ShadedVertexList;
 import com.jozufozu.flywheel.api.vertex.VertexList;
+import com.jozufozu.flywheel.core.model.ShadeSeparatedBufferBuilder;
 import com.jozufozu.flywheel.fabric.helper.BufferBuilderHelper;
 import com.jozufozu.flywheel.util.RenderMath;
 import com.mojang.blaze3d.vertex.BufferBuilder;
@@ -106,4 +108,20 @@ public class BlockVertexList implements VertexList {
 		return vertexCount;
 	}
 
+	public static class Shaded extends BlockVertexList implements ShadedVertexList {
+
+		private final int unshadedStartVertex;
+
+		public Shaded(ShadeSeparatedBufferBuilder builder) {
+			super(builder);
+			unshadedStartVertex = builder.getUnshadedStartVertex();
+		}
+
+		@Override
+		public boolean isShaded(int index) {
+			return index < unshadedStartVertex;
+		}
+
+	}
+
 }
diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexListUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexListUnsafe.java
index 7c93b29d6..0993f29e5 100644
--- a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexListUnsafe.java
+++ b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexListUnsafe.java
@@ -4,6 +4,7 @@ import java.nio.ByteBuffer;
 
 import org.lwjgl.system.MemoryUtil;
 
+import com.jozufozu.flywheel.api.vertex.ShadedVertexList;
 import com.jozufozu.flywheel.api.vertex.VertexList;
 import com.jozufozu.flywheel.util.RenderMath;
 
@@ -97,4 +98,21 @@ public class BlockVertexListUnsafe implements VertexList {
 	public int getVertexCount() {
 		return vertexCount;
 	}
+
+	public static class Shaded extends BlockVertexListUnsafe implements ShadedVertexList {
+
+		private final int unshadedStartVertex;
+
+		public Shaded(ByteBuffer buffer, int vertexCount, int unshadedStartVertex) {
+			super(buffer, vertexCount);
+			this.unshadedStartVertex = unshadedStartVertex;
+		}
+
+		@Override
+		public boolean isShaded(int index) {
+			return index < unshadedStartVertex;
+		}
+
+	}
+
 }
diff --git a/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualEmptyBlockGetter.java b/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualEmptyBlockGetter.java
index 8058bcf68..ebfbe9389 100644
--- a/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualEmptyBlockGetter.java
+++ b/src/main/java/com/jozufozu/flywheel/core/virtual/VirtualEmptyBlockGetter.java
@@ -22,115 +22,119 @@ import net.minecraft.world.level.lighting.LevelLightEngine;
 import net.minecraft.world.level.material.FluidState;
 import net.minecraft.world.level.material.Fluids;
 
-public enum VirtualEmptyBlockGetter implements BlockAndTintGetter {
-	INSTANCE;
-
-	private final LevelLightEngine lightEngine = new LevelLightEngine(new LightChunkGetter() {
-		@Override
-		public BlockGetter getChunkForLighting(int p_63023_, int p_63024_) {
-			return VirtualEmptyBlockGetter.this;
-		}
-
-		@Override
-		public BlockGetter getLevel() {
-			return VirtualEmptyBlockGetter.this;
-		}
-	}, false, false) {
-		private static final LayerLightEventListener SKY_DUMMY_LISTENER = new LayerLightEventListener() {
-			@Override
-			public void checkBlock(BlockPos pos) {
-			}
-
-			@Override
-			public void onBlockEmissionIncrease(BlockPos pos, int p_164456_) {
-			}
-
-			@Override
-			public boolean hasLightWork() {
-				return false;
-			}
-
-			@Override
-			public int runUpdates(int p_164449_, boolean p_164450_, boolean p_164451_) {
-				return p_164449_;
-			}
-
-			@Override
-			public void updateSectionStatus(SectionPos pos, boolean p_75838_) {
-			}
-
-			@Override
-			public void enableLightSources(ChunkPos pos, boolean p_164453_) {
-			}
-
-			@Override
-			public DataLayer getDataLayerData(SectionPos pos) {
-				return null;
-			}
-
-			@Override
-			public int getLightValue(BlockPos pos) {
-				return 15;
-			}
-		};
-
-		@Override
-		public LayerLightEventListener getLayerListener(LightLayer layer) {
-			if (layer == LightLayer.BLOCK) {
-				return LayerLightEventListener.DummyLightLayerEventListener.INSTANCE;
-			} else {
-				return SKY_DUMMY_LISTENER;
-			}
-		}
-
-		@Override
-		public int getRawBrightness(BlockPos pos, int skyDarken) {
-			return 15 - skyDarken;
-		}
-	};
+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 static boolean is(BlockAndTintGetter blockGetter) {
-		return blockGetter == INSTANCE;
+		return blockGetter instanceof VirtualEmptyBlockGetter;
 	}
 
 	@Override
-	public BlockEntity getBlockEntity(BlockPos pos) {
+	default BlockEntity getBlockEntity(BlockPos pos) {
 		return null;
 	}
 
 	@Override
-	public BlockState getBlockState(BlockPos pos) {
+	default BlockState getBlockState(BlockPos pos) {
 		return Blocks.AIR.defaultBlockState();
 	}
 
 	@Override
-	public FluidState getFluidState(BlockPos pos) {
+	default FluidState getFluidState(BlockPos pos) {
 		return Fluids.EMPTY.defaultFluidState();
 	}
 
 	@Override
-	public int getHeight() {
+	default int getHeight() {
 		return 1;
 	}
 
 	@Override
-	public int getMinBuildHeight() {
+	default int getMinBuildHeight() {
 		return 0;
 	}
 
 	@Override
-	public float getShade(Direction direction, boolean bool) {
+	default float getShade(Direction direction, boolean shaded) {
 		return 1f;
 	}
 
 	@Override
-	public LevelLightEngine getLightEngine() {
-		return lightEngine;
-	}
-
-	@Override
-	public int getBlockTint(BlockPos pos, ColorResolver resolver) {
+	default int getBlockTint(BlockPos pos, ColorResolver resolver) {
 		Biome plainsBiome = Minecraft.getInstance().getConnection().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY).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
+				public BlockGetter getChunkForLighting(int p_63023_, int p_63024_) {
+					return StaticLightImpl.this;
+				}
+
+				@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 void onBlockEmissionIncrease(BlockPos pos, int p_164456_) {
+				}
+
+				@Override
+				public boolean hasLightWork() {
+					return false;
+				}
+
+				@Override
+				public int runUpdates(int p_164449_, boolean p_164450_, boolean p_164451_) {
+					return p_164449_;
+				}
+
+				@Override
+				public void updateSectionStatus(SectionPos pos, boolean p_75838_) {
+				}
+
+				@Override
+				public void enableLightSources(ChunkPos pos, boolean p_164453_) {
+				}
+
+				@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/fabric/model/FabricModelUtil.java b/src/main/java/com/jozufozu/flywheel/fabric/model/FabricModelUtil.java
index 5c9044a00..5f490517c 100644
--- a/src/main/java/com/jozufozu/flywheel/fabric/model/FabricModelUtil.java
+++ b/src/main/java/com/jozufozu/flywheel/fabric/model/FabricModelUtil.java
@@ -6,9 +6,12 @@ import com.jozufozu.flywheel.Flywheel;
 
 import io.vram.frex.api.material.MaterialConstants;
 import io.vram.frex.fabric.compat.FabricMaterial;
+import io.vram.frex.fabric.compat.FabricQuadView;
 import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
 import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
+import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
 import net.fabricmc.fabric.impl.client.indigo.renderer.RenderMaterialImpl;
+import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.QuadViewImpl;
 import net.fabricmc.loader.api.FabricLoader;
 import net.minecraft.client.renderer.ItemBlockRenderTypes;
 import net.minecraft.client.renderer.RenderType;
@@ -19,6 +22,7 @@ public class FabricModelUtil {
 	public static final boolean FREX_LOADED = FabricLoader.getInstance().isModLoaded("frex");
 
 	private static final BlendModeGetter BLEND_MODE_GETTER = createBlendModeGetter();
+	private static final ShadedPredicate SHADED_PREDICATE = createShadedPredicate();
 
 	private static BlendModeGetter createBlendModeGetter() {
 		if (FREX_LOADED) {
@@ -50,7 +54,7 @@ public class FabricModelUtil {
 					return BlendMode.DEFAULT;
 				};
 			} catch (Exception e) {
-				Flywheel.LOGGER.error("Detected FREX but failed to load wrapper field.", e);
+				Flywheel.LOGGER.error("Detected FREX but failed to load material wrapper field.", e);
 				return material -> BlendMode.DEFAULT;
 			}
 		} else if (INDIUM_LOADED) {
@@ -60,10 +64,38 @@ public class FabricModelUtil {
 		}
 	}
 
+	private static ShadedPredicate createShadedPredicate() {
+		if (FREX_LOADED) {
+			try {
+				Field frexQuadViewField = FabricQuadView.class.getDeclaredField("wrapped");
+				frexQuadViewField.setAccessible(true);
+				return quad -> {
+					try {
+						io.vram.frex.api.mesh.QuadView frexQuadView = (io.vram.frex.api.mesh.QuadView) frexQuadViewField.get(quad);
+						return !frexQuadView.material().disableDiffuse();
+					} catch (Exception e) {
+					}
+					return true;
+				};
+			} catch (Exception e) {
+				Flywheel.LOGGER.error("Detected FREX but failed to load quad view wrapper field.", e);
+				return quad -> true;
+			}
+		} else if (INDIUM_LOADED) {
+			return quad -> ((link.infra.indium.renderer.mesh.QuadViewImpl) quad).hasShade();
+		} else {
+			return quad -> ((QuadViewImpl) quad).hasShade();
+		}
+	}
+
 	public static BlendMode getBlendMode(RenderMaterial material) {
 		return BLEND_MODE_GETTER.getBlendMode(material);
 	}
 
+	public static boolean isShaded(QuadView quad) {
+		return SHADED_PREDICATE.isShaded(quad);
+	}
+
 	public static boolean doesLayerMatch(BlockState modelState, RenderType layer) {
 		return ItemBlockRenderTypes.getChunkRenderType(modelState) == layer;
 	}
@@ -71,4 +103,8 @@ public class FabricModelUtil {
 	private interface BlendModeGetter {
 		BlendMode getBlendMode(RenderMaterial material);
 	}
+
+	private interface ShadedPredicate {
+		boolean isShaded(QuadView quad);
+	}
 }
diff --git a/src/main/java/com/jozufozu/flywheel/mixin/BufferBuilderMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/BufferBuilderMixin.java
index 6b13b9a92..bc82deaf8 100644
--- a/src/main/java/com/jozufozu/flywheel/mixin/BufferBuilderMixin.java
+++ b/src/main/java/com/jozufozu/flywheel/mixin/BufferBuilderMixin.java
@@ -20,16 +20,10 @@ public abstract class BufferBuilderMixin implements BufferBuilderExtension {
 	private ByteBuffer buffer;
 
 	@Shadow
-	private boolean building;
+	private int nextElementByte;
 
 	@Shadow
-	public abstract void begin(VertexFormat.Mode p_166780_, VertexFormat p_166781_);
-
-	@Shadow
-	private VertexFormat.Mode mode;
-
-	@Shadow
-	private VertexFormat format;
+	private int vertices;
 
 	@Shadow
 	@Nullable
@@ -39,7 +33,22 @@ public abstract class BufferBuilderMixin implements BufferBuilderExtension {
 	private int elementIndex;
 
 	@Shadow
-	private int vertices;
+	private VertexFormat format;
+
+	@Shadow
+	private VertexFormat.Mode mode;
+
+	@Shadow
+	private boolean building;
+
+	@Shadow
+	private void ensureCapacity(int increaseAmount) {
+	}
+
+	@Override
+	public int flywheel$getVertices() {
+		return vertices;
+	}
 
 	@Override
 	public void flywheel$freeBuffer() {
@@ -61,4 +70,29 @@ public abstract class BufferBuilderMixin implements BufferBuilderExtension {
 		this.currentElement = this.format.getElements().get(0);
 		this.elementIndex = 0;
 	}
+
+	@Override
+	public void flywheel$appendBufferUnsafe(ByteBuffer buffer) {
+		if (!building) {
+			throw new IllegalStateException("BufferBuilder not started");
+		}
+		if (elementIndex != 0) {
+			throw new IllegalStateException("Cannot append buffer while building vertex");
+		}
+
+		int numBytes = buffer.remaining();
+		if (numBytes % format.getVertexSize() != 0) {
+			throw new IllegalArgumentException("Cannot append buffer with non-whole number of vertices");
+		}
+		int numVertices = numBytes / format.getVertexSize();
+
+		ensureCapacity(numBytes + format.getVertexSize());
+		int originalPosition = this.buffer.position();
+		this.buffer.position(nextElementByte);
+		MemoryUtil.memCopy(buffer, this.buffer);
+		this.buffer.position(originalPosition);
+
+		nextElementByte += numBytes;
+		vertices += numVertices;
+	}
 }
diff --git a/src/main/java/com/jozufozu/flywheel/util/DiffuseLightCalculator.java b/src/main/java/com/jozufozu/flywheel/util/DiffuseLightCalculator.java
index 4fc5eeaf4..4f1ac0557 100644
--- a/src/main/java/com/jozufozu/flywheel/util/DiffuseLightCalculator.java
+++ b/src/main/java/com/jozufozu/flywheel/util/DiffuseLightCalculator.java
@@ -15,5 +15,5 @@ public interface DiffuseLightCalculator {
 		return level.effects().constantAmbientLight() ? NETHER : DEFAULT;
 	}
 
-	float getDiffuse(float normalX, float normalY, float normalZ);
+	float getDiffuse(float normalX, float normalY, float normalZ, boolean shaded);
 }
diff --git a/src/main/java/com/jozufozu/flywheel/util/RenderMath.java b/src/main/java/com/jozufozu/flywheel/util/RenderMath.java
index 9244d91f4..16d223a8f 100644
--- a/src/main/java/com/jozufozu/flywheel/util/RenderMath.java
+++ b/src/main/java/com/jozufozu/flywheel/util/RenderMath.java
@@ -68,11 +68,17 @@ public class RenderMath {
 		return (float) (((((target - current) % 360) + 540) % 360) - 180);
 	}
 
-	public static float diffuseLight(float x, float y, float z) {
+	public static float diffuseLight(float x, float y, float z, boolean shaded) {
+		if (!shaded) {
+			return 1f;
+		}
 		return Math.min(x * x * 0.6f + y * y * ((3f + y) / 4f) + z * z * 0.8f, 1f);
 	}
 
-	public static float diffuseLightNether(float x, float y, float z) {
+	public static float diffuseLightNether(float x, float y, float z, boolean shaded) {
+		if (!shaded) {
+			return 0.9f;
+		}
 		return Math.min(x * x * 0.6f + y * y * 0.9f + z * z * 0.8f, 1f);
 	}
 }
diff --git a/src/main/java/com/jozufozu/flywheel/util/TextureBinder.java b/src/main/java/com/jozufozu/flywheel/util/TextureBinder.java
deleted file mode 100644
index e90435078..000000000
--- a/src/main/java/com/jozufozu/flywheel/util/TextureBinder.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.jozufozu.flywheel.util;
-
-import net.minecraft.client.renderer.RenderType;
-
-/**
- * This is a silly hack that's needed because flywheel does things too different from vanilla.
- *
- * 

- * When a {@link RenderType} is setup, the associated textures are "bound" within RenderSystem, but not actually - * bound via opengl. This class provides a helper function to forward the bindings to opengl. - *

- */ -public class TextureBinder { - -} diff --git a/src/main/resources/assets/flywheel/flywheel/shaders/context/crumbling.glsl b/src/main/resources/assets/flywheel/flywheel/shaders/context/crumbling.glsl index 958941126..423977c8a 100644 --- a/src/main/resources/assets/flywheel/flywheel/shaders/context/crumbling.glsl +++ b/src/main/resources/assets/flywheel/flywheel/shaders/context/crumbling.glsl @@ -1,5 +1,4 @@ #use "flywheel:context/fog.glsl" -#use "flywheel:core/diffuse.glsl" uniform float uTime; uniform mat4 uViewProjection; diff --git a/src/main/resources/assets/flywheel/flywheel/shaders/context/world.glsl b/src/main/resources/assets/flywheel/flywheel/shaders/context/world.glsl index 28e36ab3d..b6386e92d 100644 --- a/src/main/resources/assets/flywheel/flywheel/shaders/context/world.glsl +++ b/src/main/resources/assets/flywheel/flywheel/shaders/context/world.glsl @@ -1,5 +1,4 @@ #use "flywheel:context/fog.glsl" -#use "flywheel:core/diffuse.glsl" uniform float uTime; uniform mat4 uViewProjection;