mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-07 02:34:58 +01:00
Better buffering
- Abstract ModelUtil.getBufferBuilder and .getBufferBuilderFromTemplate - BakedModelBuilder and WorldModelBuilder as parameter objects for getBufferBuilder - WorldModelBuilder supports IModelData
This commit is contained in:
parent
8e069d9209
commit
303a58b277
7 changed files with 180 additions and 73 deletions
|
@ -4,6 +4,8 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.client.event.ModelBakeEvent;
|
||||
|
@ -49,6 +51,12 @@ public class PartialModel {
|
|||
partial.set(modelRegistry.get(partial.getLocation()));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getName() {
|
||||
return getLocation()
|
||||
.toString();
|
||||
}
|
||||
|
||||
protected void set(BakedModel bakedModel) {
|
||||
this.bakedModel = bakedModel;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -7,7 +7,6 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
|||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
/**
|
||||
|
@ -35,11 +34,18 @@ public class BlockModel implements Model {
|
|||
}
|
||||
|
||||
public BlockModel(PartialModel model, PoseStack ms) {
|
||||
this(Formats.BLOCK.createReader(ModelUtil.getBufferBuilder(model.get(), Blocks.AIR.defaultBlockState(), ms)), model.getLocation().toString());
|
||||
this(ModelUtil.bakedModel(model.get())
|
||||
.withPoseStack(ms), model.getName());
|
||||
}
|
||||
|
||||
public BlockModel(BakedModel model, BlockState referenceState, PoseStack ms) {
|
||||
this(Formats.BLOCK.createReader(ModelUtil.getBufferBuilder(model, referenceState, ms)), referenceState.toString());
|
||||
this(ModelUtil.bakedModel(model)
|
||||
.withReferenceState(referenceState)
|
||||
.withPoseStack(ms), referenceState.toString());
|
||||
}
|
||||
|
||||
public BlockModel(BakedModelBuilder builder, String name) {
|
||||
this(Formats.BLOCK.createReader(builder.build()), name);
|
||||
}
|
||||
|
||||
public BlockModel(VertexList reader, String name) {
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -1,13 +1,10 @@
|
|||
package com.jozufozu.flywheel.core.model;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Random;
|
||||
|
||||
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 +12,11 @@ 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,72 +44,29 @@ public class ModelUtil {
|
|||
return dispatcher;
|
||||
}
|
||||
|
||||
public static ShadeSeparatedBufferBuilder getBufferBuilder(BakedModel model, BlockState referenceState, PoseStack poseStack) {
|
||||
return getBufferBuilder(VirtualEmptyBlockGetter.INSTANCE, model, referenceState, poseStack);
|
||||
public static BakedModelBuilder bakedModel(BakedModel model) {
|
||||
return new BakedModelBuilder(model);
|
||||
}
|
||||
|
||||
public static ShadeSeparatedBufferBuilder getBufferBuilder(BlockAndTintGetter renderWorld, BakedModel model, BlockState referenceState, PoseStack poseStack) {
|
||||
public static WorldModelBuilder worldLayer(RenderType layer) {
|
||||
return new WorldModelBuilder(layer);
|
||||
}
|
||||
|
||||
public static ShadeSeparatedBufferBuilder getBufferBuilder(Bufferable object) {
|
||||
ModelBlockRenderer blockRenderer = VANILLA_RENDERER.getModelRenderer();
|
||||
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);
|
||||
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();
|
||||
objects.unshadedBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
||||
objects.shadeSeparatingWrapper.prepare(builder, objects.unshadedBuilder);
|
||||
|
||||
return builder;
|
||||
}
|
||||
object.bufferInto(blockRenderer, objects.shadeSeparatingWrapper, objects.random);
|
||||
|
||||
public static ShadeSeparatedBufferBuilder getBufferBuilderFromTemplate(BlockAndTintGetter renderWorld, RenderType layer, Collection<StructureTemplate.StructureBlockInfo> blocks) {
|
||||
return getBufferBuilderFromTemplate(renderWorld, layer, blocks, new PoseStack());
|
||||
}
|
||||
|
||||
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);
|
||||
objects.shadeSeparatingWrapper.clear();
|
||||
objects.unshadedBuilder.end();
|
||||
builder.appendUnshadedVertices(objects.unshadedBuilder);
|
||||
builder.end();
|
||||
|
||||
return builder;
|
||||
|
@ -148,9 +93,10 @@ public class ModelUtil {
|
|||
}
|
||||
}
|
||||
|
||||
private static class ThreadLocalObjects {
|
||||
private static class ThreadLocalObjects {
|
||||
public final Random random = new Random();
|
||||
public final ShadeSeparatingVertexConsumer shadeSeparatingWrapper = new ShadeSeparatingVertexConsumer();
|
||||
public final BufferBuilder unshadedBuilder = new BufferBuilder(512);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,10 @@ public class WorldModel implements Model {
|
|||
* 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));
|
||||
reader = Formats.BLOCK.createReader(ModelUtil.worldLayer(layer)
|
||||
.withBlocks(blocks)
|
||||
.withRenderWorld(renderWorld)
|
||||
.build());
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue