mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-27 07:26:48 +01:00
World building exercise
- Yoink the WorldModelBuilder and associated changes from 1.18/next
This commit is contained in:
parent
273c99619f
commit
faa5652c4c
7 changed files with 216 additions and 85 deletions
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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<StructureTemplate.StructureBlockInfo> 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<StructureTemplate.StructureBlockInfo> 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<PoseStack> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<StructureTemplate.StructureBlockInfo> 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<BlockPos, IModelData> modelData = Collections.emptyMap();
|
||||
private BlockAndTintGetter renderWorld = VirtualEmptyBlockGetter.INSTANCE;
|
||||
private Collection<StructureTemplate.StructureBlockInfo> 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<StructureTemplate.StructureBlockInfo> blocks) {
|
||||
this.blocks = blocks;
|
||||
return this;
|
||||
}
|
||||
|
||||
public WorldModelBuilder withModelData(Map<BlockPos, IModelData> 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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue