From faa5652c4cba174d2797f1fdf39812b72dbc623e Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Sun, 10 Jul 2022 19:04:30 -0400 Subject: [PATCH] World building exercise - Yoink the WorldModelBuilder and associated changes from 1.18/next --- .../core/model/BakedModelBuilder.java | 48 ++++++++ .../flywheel/core/model/Bufferable.java | 19 ++++ .../flywheel/core/model/ModelUtil.java | 106 +++++++----------- .../flywheel/core/model/WorldModel.java | 14 +-- .../core/model/WorldModelBuilder.java | 86 ++++++++++++++ .../core/vertex/BlockVertexListUnsafe.java | 14 ++- .../vertex/PosTexNormalVertexListUnsafe.java | 14 ++- 7 files changed, 216 insertions(+), 85 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/core/model/BakedModelBuilder.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/model/Bufferable.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/model/WorldModelBuilder.java diff --git a/src/main/java/com/jozufozu/flywheel/core/model/BakedModelBuilder.java b/src/main/java/com/jozufozu/flywheel/core/model/BakedModelBuilder.java new file mode 100644 index 000000000..70631ebea --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/BakedModelBuilder.java @@ -0,0 +1,48 @@ + +package com.jozufozu.flywheel.core.model; + +import java.util.Random; + +import com.jozufozu.flywheel.core.virtual.VirtualEmptyBlockGetter; +import com.jozufozu.flywheel.core.virtual.VirtualEmptyModelData; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; + +import net.minecraft.client.renderer.block.ModelBlockRenderer; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; + +public final class BakedModelBuilder implements Bufferable { + private final BakedModel model; + private BlockAndTintGetter renderWorld = VirtualEmptyBlockGetter.INSTANCE; + private BlockState referenceState = Blocks.AIR.defaultBlockState(); + private PoseStack poseStack = new PoseStack(); + + public BakedModelBuilder(BakedModel model) { + this.model = model; + } + + public BakedModelBuilder withRenderWorld(BlockAndTintGetter renderWorld) { + this.renderWorld = renderWorld; + return this; + } + + public BakedModelBuilder withReferenceState(BlockState referenceState) { + this.referenceState = referenceState; + return this; + } + + public BakedModelBuilder withPoseStack(PoseStack poseStack) { + this.poseStack = poseStack; + return this; + } + + @Override + public void bufferInto(ModelBlockRenderer blockRenderer, VertexConsumer consumer, Random random) { + blockRenderer.tesselateBlock(renderWorld, model, referenceState, BlockPos.ZERO, poseStack, consumer, false, random, 42, OverlayTexture.NO_OVERLAY, VirtualEmptyModelData.INSTANCE); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/Bufferable.java b/src/main/java/com/jozufozu/flywheel/core/model/Bufferable.java new file mode 100644 index 000000000..ee78333ad --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/Bufferable.java @@ -0,0 +1,19 @@ + +package com.jozufozu.flywheel.core.model; + +import java.util.Random; + +import com.mojang.blaze3d.vertex.VertexConsumer; + +import net.minecraft.client.renderer.block.ModelBlockRenderer; + +/** + * An interface for objects that can "rendered" into a BufferBuilder. + */ +public interface Bufferable { + void bufferInto(ModelBlockRenderer renderer, VertexConsumer consumer, Random random); + + default ShadeSeparatedBufferBuilder build() { + return ModelUtil.getBufferBuilder(this); + } +} 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 0815adf28..1cd4f903c 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/ModelUtil.java @@ -6,8 +6,6 @@ import java.util.Random; import java.util.function.Supplier; import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.core.virtual.VirtualEmptyBlockGetter; -import com.jozufozu.flywheel.core.virtual.VirtualEmptyModelData; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.DefaultVertexFormat; @@ -15,20 +13,14 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexFormat; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.ItemBlockRenderTypes; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.block.BlockRenderDispatcher; import net.minecraft.client.renderer.block.ModelBlockRenderer; -import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.RenderShape; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; -import net.minecraftforge.client.ForgeHooksClient; -import net.minecraftforge.client.model.data.EmptyModelData; import net.minecraftforge.fml.util.ObfuscationReflectionHelper; public class ModelUtil { @@ -56,75 +48,43 @@ public class ModelUtil { return dispatcher; } - 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) { + public static ShadeSeparatedBufferBuilder getBufferBuilder(Bufferable bufferable) { ModelBlockRenderer blockRenderer = VANILLA_RENDERER.getModelRenderer(); ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get(); - ShadeSeparatingVertexConsumer shadeSeparatingWrapper = objects.shadeSeparatingWrapper; - ShadeSeparatedBufferBuilder builder = new ShadeSeparatedBufferBuilder(512); - BufferBuilder unshadedBuilder = objects.unshadedBuilder; + objects.begin(); - builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); - unshadedBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); - shadeSeparatingWrapper.prepare(builder, unshadedBuilder); - blockRenderer.tesselateBlock(renderWorld, model, referenceState, BlockPos.ZERO, poseStack, shadeSeparatingWrapper, - false, objects.random, 42, OverlayTexture.NO_OVERLAY, VirtualEmptyModelData.INSTANCE); - shadeSeparatingWrapper.clear(); - unshadedBuilder.end(); - builder.appendUnshadedVertices(unshadedBuilder); - builder.end(); + bufferable.bufferInto(blockRenderer, objects.shadeSeparatingWrapper, objects.random); - return builder; + objects.end(); + + return objects.separatedBufferBuilder; + } + + public static ShadeSeparatedBufferBuilder getBufferBuilder(BakedModel model, BlockState referenceState, PoseStack poseStack) { + return new BakedModelBuilder(model).withReferenceState(referenceState) + .withPoseStack(poseStack) + .build(); + } + + public static ShadeSeparatedBufferBuilder getBufferBuilder(BlockAndTintGetter renderWorld, BakedModel model, BlockState referenceState, PoseStack poseStack) { + return new BakedModelBuilder(model).withReferenceState(referenceState) + .withPoseStack(poseStack) + .withRenderWorld(renderWorld) + .build(); } public static ShadeSeparatedBufferBuilder getBufferBuilderFromTemplate(BlockAndTintGetter renderWorld, RenderType layer, Collection blocks) { - return getBufferBuilderFromTemplate(renderWorld, layer, blocks, new PoseStack()); + return new WorldModelBuilder(layer).withRenderWorld(renderWorld) + .withBlocks(blocks) + .build(); } public static ShadeSeparatedBufferBuilder getBufferBuilderFromTemplate(BlockAndTintGetter renderWorld, RenderType layer, Collection blocks, PoseStack poseStack) { - ModelBlockRenderer modelRenderer = VANILLA_RENDERER.getModelRenderer(); - ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get(); - - Random random = objects.random; - 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); - - ForgeHooksClient.setRenderType(layer); - ModelBlockRenderer.enableCaching(); - for (StructureTemplate.StructureBlockInfo info : blocks) { - BlockState state = info.state; - - if (state.getRenderShape() != RenderShape.MODEL) - continue; - if (!ItemBlockRenderTypes.canRenderInLayer(state, layer)) - continue; - - BlockPos pos = info.pos; - - poseStack.pushPose(); - poseStack.translate(pos.getX(), pos.getY(), pos.getZ()); - modelRenderer.tesselateBlock(renderWorld, VANILLA_RENDERER.getBlockModel(state), state, pos, poseStack, shadeSeparatingWrapper, - true, random, 42, OverlayTexture.NO_OVERLAY, EmptyModelData.INSTANCE); - poseStack.popPose(); - } - ModelBlockRenderer.clearCache(); - ForgeHooksClient.setRenderType(null); - - shadeSeparatingWrapper.clear(); - unshadedBuilder.end(); - builder.appendUnshadedVertices(unshadedBuilder); - builder.end(); - - return builder; + return new WorldModelBuilder(layer).withRenderWorld(renderWorld) + .withBlocks(blocks) + .withPoseStack(poseStack) + .build(); } public static Supplier rotateToFace(Direction facing) { @@ -141,6 +101,20 @@ public class ModelUtil { private static class ThreadLocalObjects { public final Random random = new Random(); public final ShadeSeparatingVertexConsumer shadeSeparatingWrapper = new ShadeSeparatingVertexConsumer(); + public final ShadeSeparatedBufferBuilder separatedBufferBuilder = new ShadeSeparatedBufferBuilder(512); public final BufferBuilder unshadedBuilder = new BufferBuilder(512); + + private void begin() { + this.separatedBufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); + this.unshadedBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); + this.shadeSeparatingWrapper.prepare(this.separatedBufferBuilder, this.unshadedBuilder); + } + + private void end() { + this.shadeSeparatingWrapper.clear(); + this.unshadedBuilder.end(); + this.separatedBufferBuilder.appendUnshadedVertices(this.unshadedBuilder); + this.separatedBufferBuilder.end(); + } } } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/WorldModel.java b/src/main/java/com/jozufozu/flywheel/core/model/WorldModel.java index c350361c9..c144f43c6 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/WorldModel.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/WorldModel.java @@ -1,25 +1,17 @@ package com.jozufozu.flywheel.core.model; -import java.util.Collection; - import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.core.Formats; - -import net.minecraft.client.renderer.RenderType; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; +import com.mojang.blaze3d.vertex.BufferBuilder; public class WorldModel implements Model { private final VertexList reader; private final String name; - /** - * It is expected that {@code renderWorld.getShade(...)} returns a constant. - */ - public WorldModel(BlockAndTintGetter renderWorld, RenderType layer, Collection blocks, String name) { - reader = Formats.BLOCK.createReader(ModelUtil.getBufferBuilderFromTemplate(renderWorld, layer, blocks)); + public WorldModel(BufferBuilder bufferBuilder, String name) { + this.reader = Formats.BLOCK.createReader(bufferBuilder); this.name = name; } diff --git a/src/main/java/com/jozufozu/flywheel/core/model/WorldModelBuilder.java b/src/main/java/com/jozufozu/flywheel/core/model/WorldModelBuilder.java new file mode 100644 index 000000000..38bda7d1c --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/WorldModelBuilder.java @@ -0,0 +1,86 @@ +package com.jozufozu.flywheel.core.model; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Random; + +import com.jozufozu.flywheel.core.virtual.VirtualEmptyBlockGetter; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; + +import net.minecraft.client.renderer.ItemBlockRenderTypes; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.ModelBlockRenderer; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.core.BlockPos; +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.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.client.model.data.EmptyModelData; +import net.minecraftforge.client.model.data.IModelData; + +public final class WorldModelBuilder implements Bufferable { + private final RenderType layer; + + private PoseStack poseStack = new PoseStack(); + private Map modelData = Collections.emptyMap(); + private BlockAndTintGetter renderWorld = VirtualEmptyBlockGetter.INSTANCE; + private Collection blocks = Collections.emptyList(); + + public WorldModelBuilder(RenderType layer) { + this.layer = layer; + } + + @Override + public void bufferInto(ModelBlockRenderer modelRenderer, VertexConsumer consumer, Random random) { + ForgeHooksClient.setRenderType(this.layer); + ModelBlockRenderer.enableCaching(); + for (StructureTemplate.StructureBlockInfo info : this.blocks) { + BlockState state = info.state; + + if (state.getRenderShape() != RenderShape.MODEL) continue; + if (!ItemBlockRenderTypes.canRenderInLayer(state, this.layer)) continue; + + BlockPos pos = info.pos; + + IModelData data = this.modelData.getOrDefault(pos, EmptyModelData.INSTANCE); + + poseStack.pushPose(); + poseStack.translate(pos.getX(), pos.getY(), pos.getZ()); + modelRenderer.tesselateBlock(this.renderWorld, ModelUtil.VANILLA_RENDERER.getBlockModel(state), state, pos, poseStack, consumer, true, random, 42, OverlayTexture.NO_OVERLAY, data); + poseStack.popPose(); + } + ModelBlockRenderer.clearCache(); + ForgeHooksClient.setRenderType(null); + } + + /** + * It is expected that {@code renderWorld.getShade(...)} returns a constant. + */ + public WorldModelBuilder withRenderWorld(BlockAndTintGetter renderWorld) { + this.renderWorld = renderWorld; + return this; + } + + public WorldModelBuilder withBlocks(Collection blocks) { + this.blocks = blocks; + return this; + } + + public WorldModelBuilder withModelData(Map modelData) { + this.modelData = modelData; + return this; + } + + public WorldModelBuilder withPoseStack(PoseStack poseStack) { + this.poseStack = poseStack; + return this; + } + + public WorldModel intoMesh(String name) { + return new WorldModel(ModelUtil.getBufferBuilder(this), name); + } +} 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 0993f29e5..839687a7e 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexListUnsafe.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexListUnsafe.java @@ -1,5 +1,6 @@ package com.jozufozu.flywheel.core.vertex; +import java.nio.Buffer; import java.nio.ByteBuffer; import org.lwjgl.system.MemoryUtil; @@ -7,16 +8,21 @@ 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; +import com.mojang.blaze3d.platform.MemoryTracker; public class BlockVertexListUnsafe implements VertexList { - private final ByteBuffer buffer; + private final ByteBuffer contents; private final int vertexCount; private final long base; - public BlockVertexListUnsafe(ByteBuffer buffer, int vertexCount) { - this.buffer = buffer; - this.base = MemoryUtil.memAddress(buffer); + public BlockVertexListUnsafe(ByteBuffer copyFrom, int vertexCount) { + this.contents = MemoryTracker.create(copyFrom.capacity()); + this.contents.order(copyFrom.order()); + this.contents.put(copyFrom); + ((Buffer) this.contents).flip(); + + this.base = MemoryUtil.memAddress(this.contents); this.vertexCount = vertexCount; } diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertexListUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertexListUnsafe.java index 70d4a72ee..e94861b47 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertexListUnsafe.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertexListUnsafe.java @@ -1,22 +1,28 @@ package com.jozufozu.flywheel.core.vertex; +import java.nio.Buffer; import java.nio.ByteBuffer; import org.lwjgl.system.MemoryUtil; import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.util.RenderMath; +import com.mojang.blaze3d.platform.MemoryTracker; public class PosTexNormalVertexListUnsafe implements VertexList { - private final ByteBuffer buffer; + private final ByteBuffer contents; private final int vertexCount; private final long base; - public PosTexNormalVertexListUnsafe(ByteBuffer buffer, int vertexCount) { - this.buffer = buffer; + public PosTexNormalVertexListUnsafe(ByteBuffer copyFrom, int vertexCount) { + this.contents = MemoryTracker.create(copyFrom.capacity()); + this.contents.order(copyFrom.order()); + this.contents.put(copyFrom); + ((Buffer) this.contents).flip(); + + this.base = MemoryUtil.memAddress(this.contents); this.vertexCount = vertexCount; - this.base = MemoryUtil.memAddress(buffer); } private long ptr(long idx) {