mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-03 08:44:57 +01:00
Best-effort untested Fabric model builders
- Also fix crash buffering fluids in BakedModelBufferer#bufferMultiBlock (Forge) - The mesh order in models created by model builders is currently incorrect and will be fixed later
This commit is contained in:
parent
9ae4065c1c
commit
b9490fe11a
19 changed files with 853 additions and 219 deletions
|
@ -2,6 +2,7 @@ package com.jozufozu.flywheel.lib.model.baked;
|
||||||
|
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.material.Material;
|
import com.jozufozu.flywheel.api.material.Material;
|
||||||
|
@ -14,25 +15,26 @@ import net.minecraft.client.resources.model.BakedModel;
|
||||||
import net.minecraft.world.level.BlockAndTintGetter;
|
import net.minecraft.world.level.BlockAndTintGetter;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
|
||||||
|
@ApiStatus.NonExtendable
|
||||||
public abstract class BakedModelBuilder {
|
public abstract class BakedModelBuilder {
|
||||||
protected final BakedModel bakedModel;
|
final BakedModel bakedModel;
|
||||||
@Nullable
|
@Nullable
|
||||||
protected BlockAndTintGetter level;
|
BlockAndTintGetter level;
|
||||||
@Nullable
|
@Nullable
|
||||||
protected BlockState blockState;
|
BlockState blockState;
|
||||||
@Nullable
|
@Nullable
|
||||||
protected PoseStack poseStack;
|
PoseStack poseStack;
|
||||||
@Nullable
|
@Nullable
|
||||||
protected BiFunction<RenderType, Boolean, Material> materialFunc;
|
BiFunction<RenderType, Boolean, Material> materialFunc;
|
||||||
|
|
||||||
|
BakedModelBuilder(BakedModel bakedModel) {
|
||||||
|
this.bakedModel = bakedModel;
|
||||||
|
}
|
||||||
|
|
||||||
public static BakedModelBuilder create(BakedModel bakedModel) {
|
public static BakedModelBuilder create(BakedModel bakedModel) {
|
||||||
return FlwLibXplat.INSTANCE.createBakedModelBuilder(bakedModel);
|
return FlwLibXplat.INSTANCE.createBakedModelBuilder(bakedModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BakedModelBuilder(BakedModel bakedModel) {
|
|
||||||
this.bakedModel = bakedModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BakedModelBuilder level(BlockAndTintGetter level) {
|
public BakedModelBuilder level(BlockAndTintGetter level) {
|
||||||
this.level = level;
|
this.level = level;
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.jozufozu.flywheel.lib.model.baked;
|
||||||
|
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.material.Material;
|
import com.jozufozu.flywheel.api.material.Material;
|
||||||
|
@ -13,23 +14,24 @@ import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.world.level.BlockAndTintGetter;
|
import net.minecraft.world.level.BlockAndTintGetter;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
|
||||||
|
@ApiStatus.NonExtendable
|
||||||
public abstract class BlockModelBuilder {
|
public abstract class BlockModelBuilder {
|
||||||
protected final BlockState state;
|
final BlockState state;
|
||||||
@Nullable
|
@Nullable
|
||||||
protected BlockAndTintGetter level;
|
BlockAndTintGetter level;
|
||||||
@Nullable
|
@Nullable
|
||||||
protected PoseStack poseStack;
|
PoseStack poseStack;
|
||||||
@Nullable
|
@Nullable
|
||||||
protected BiFunction<RenderType, Boolean, Material> materialFunc;
|
BiFunction<RenderType, Boolean, Material> materialFunc;
|
||||||
|
|
||||||
|
BlockModelBuilder(BlockState state) {
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
public static BlockModelBuilder create(BlockState state) {
|
public static BlockModelBuilder create(BlockState state) {
|
||||||
return FlwLibXplat.INSTANCE.createBlockModelBuilder(state);
|
return FlwLibXplat.INSTANCE.createBlockModelBuilder(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BlockModelBuilder(BlockState state) {
|
|
||||||
this.state = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockModelBuilder level(BlockAndTintGetter level) {
|
public BlockModelBuilder level(BlockAndTintGetter level) {
|
||||||
this.level = level;
|
this.level = level;
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -1,119 +0,0 @@
|
||||||
package com.jozufozu.flywheel.lib.model.baked;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
|
||||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
|
||||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
|
||||||
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
|
||||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
|
||||||
|
|
||||||
class MeshEmitter implements VertexConsumer {
|
|
||||||
protected final BufferBuilder bufferBuilder;
|
|
||||||
private final RenderType renderType;
|
|
||||||
private boolean lastQuadWasShaded;
|
|
||||||
private boolean seenFirstQuad;
|
|
||||||
@Nullable
|
|
||||||
private MeshEmitter.ResultConsumer resultConsumer;
|
|
||||||
|
|
||||||
MeshEmitter(BufferBuilder bufferBuilder, RenderType renderType) {
|
|
||||||
this.bufferBuilder = bufferBuilder;
|
|
||||||
this.renderType = renderType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void begin(ResultConsumer resultConsumer) {
|
|
||||||
this.resultConsumer = resultConsumer;
|
|
||||||
|
|
||||||
begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void end() {
|
|
||||||
emit();
|
|
||||||
seenFirstQuad = false;
|
|
||||||
resultConsumer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void begin() {
|
|
||||||
bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void emit() {
|
|
||||||
var renderedBuffer = bufferBuilder.endOrDiscardIfEmpty();
|
|
||||||
|
|
||||||
if (renderedBuffer != null) {
|
|
||||||
if (resultConsumer != null) {
|
|
||||||
resultConsumer.accept(renderType, lastQuadWasShaded, renderedBuffer);
|
|
||||||
}
|
|
||||||
renderedBuffer.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void observeQuadAndEmitIfNecessary(BakedQuad quad) {
|
|
||||||
if (seenFirstQuad && lastQuadWasShaded != quad.isShade()) {
|
|
||||||
emit();
|
|
||||||
begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
seenFirstQuad = true;
|
|
||||||
lastQuadWasShaded = quad.isShade();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void putBulkData(PoseStack.Pose poseEntry, BakedQuad quad, float[] colorMuls, float red, float green, float blue, int[] combinedLights, int combinedOverlay, boolean mulColor) {
|
|
||||||
observeQuadAndEmitIfNecessary(quad);
|
|
||||||
|
|
||||||
bufferBuilder.putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VertexConsumer vertex(double x, double y, double z) {
|
|
||||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VertexConsumer color(int red, int green, int blue, int alpha) {
|
|
||||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VertexConsumer uv(float u, float v) {
|
|
||||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VertexConsumer overlayCoords(int u, int v) {
|
|
||||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VertexConsumer uv2(int u, int v) {
|
|
||||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public VertexConsumer normal(float x, float y, float z) {
|
|
||||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void endVertex() {
|
|
||||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void defaultColor(int red, int green, int blue, int alpha) {
|
|
||||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unsetDefaultColor() {
|
|
||||||
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface ResultConsumer {
|
|
||||||
void accept(RenderType renderType, boolean shaded, BufferBuilder.RenderedBuffer data);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,6 +2,7 @@ package com.jozufozu.flywheel.lib.model.baked;
|
||||||
|
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.material.Material;
|
import com.jozufozu.flywheel.api.material.Material;
|
||||||
|
@ -13,24 +14,25 @@ import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.level.BlockAndTintGetter;
|
import net.minecraft.world.level.BlockAndTintGetter;
|
||||||
|
|
||||||
|
@ApiStatus.NonExtendable
|
||||||
public abstract class MultiBlockModelBuilder {
|
public abstract class MultiBlockModelBuilder {
|
||||||
protected final BlockAndTintGetter level;
|
final BlockAndTintGetter level;
|
||||||
protected final Iterable<BlockPos> positions;
|
final Iterable<BlockPos> positions;
|
||||||
@Nullable
|
@Nullable
|
||||||
protected PoseStack poseStack;
|
PoseStack poseStack;
|
||||||
protected boolean renderFluids = false;
|
boolean renderFluids = false;
|
||||||
@Nullable
|
@Nullable
|
||||||
protected BiFunction<RenderType, Boolean, Material> materialFunc;
|
BiFunction<RenderType, Boolean, Material> materialFunc;
|
||||||
|
|
||||||
|
MultiBlockModelBuilder(BlockAndTintGetter level, Iterable<BlockPos> positions) {
|
||||||
|
this.level = level;
|
||||||
|
this.positions = positions;
|
||||||
|
}
|
||||||
|
|
||||||
public static MultiBlockModelBuilder create(BlockAndTintGetter level, Iterable<BlockPos> positions) {
|
public static MultiBlockModelBuilder create(BlockAndTintGetter level, Iterable<BlockPos> positions) {
|
||||||
return FlwLibXplat.INSTANCE.createMultiBlockModelBuilder(level, positions);
|
return FlwLibXplat.INSTANCE.createMultiBlockModelBuilder(level, positions);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MultiBlockModelBuilder(BlockAndTintGetter level, Iterable<BlockPos> positions) {
|
|
||||||
this.level = level;
|
|
||||||
this.positions = positions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MultiBlockModelBuilder poseStack(PoseStack poseStack) {
|
public MultiBlockModelBuilder poseStack(PoseStack poseStack) {
|
||||||
this.poseStack = poseStack;
|
this.poseStack = poseStack;
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.jozufozu.flywheel.lib.model.baked;
|
package com.jozufozu.flywheel.lib.model.baked;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.UnknownNullability;
|
||||||
import org.joml.Matrix3f;
|
import org.joml.Matrix3f;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
|
|
||||||
|
@ -8,7 +9,9 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
|
||||||
class TransformingVertexConsumer implements VertexConsumer {
|
class TransformingVertexConsumer implements VertexConsumer {
|
||||||
|
@UnknownNullability
|
||||||
private VertexConsumer delegate;
|
private VertexConsumer delegate;
|
||||||
|
@UnknownNullability
|
||||||
private PoseStack poseStack;
|
private PoseStack poseStack;
|
||||||
|
|
||||||
public void prepare(VertexConsumer delegate, PoseStack poseStack) {
|
public void prepare(VertexConsumer delegate, PoseStack poseStack) {
|
||||||
|
|
|
@ -15,7 +15,7 @@ import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.world.level.LightLayer;
|
import net.minecraft.world.level.LightLayer;
|
||||||
|
|
||||||
@Mixin(ClientChunkCache.class)
|
@Mixin(ClientChunkCache.class)
|
||||||
public class ClientChunkCacheMixin {
|
abstract class ClientChunkCacheMixin {
|
||||||
@Shadow
|
@Shadow
|
||||||
@Final
|
@Final
|
||||||
ClientLevel level;
|
ClientLevel level;
|
||||||
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
package com.jozufozu.flywheel.lib.model.baked;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.BufferBuilder.RenderedBuffer;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
|
||||||
|
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.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.material.FluidState;
|
||||||
|
|
||||||
|
final class BakedModelBufferer {
|
||||||
|
private static final RenderType[] CHUNK_LAYERS = RenderType.chunkBufferLayers().toArray(RenderType[]::new);
|
||||||
|
private static final int CHUNK_LAYER_AMOUNT = CHUNK_LAYERS.length;
|
||||||
|
|
||||||
|
private static final ThreadLocal<ThreadLocalObjects> THREAD_LOCAL_OBJECTS = ThreadLocal.withInitial(ThreadLocalObjects::new);
|
||||||
|
|
||||||
|
private BakedModelBufferer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bufferSingle(ModelBlockRenderer blockRenderer, BlockAndTintGetter level, BakedModel model, BlockState state, @Nullable PoseStack poseStack, ResultConsumer resultConsumer) {
|
||||||
|
ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
|
||||||
|
if (poseStack == null) {
|
||||||
|
poseStack = objects.identityPoseStack;
|
||||||
|
}
|
||||||
|
RandomSource random = objects.random;
|
||||||
|
MeshEmitter[] emitters = objects.emitters;
|
||||||
|
UniversalMeshEmitter universalEmitter = objects.universalEmitter;
|
||||||
|
|
||||||
|
for (MeshEmitter emitter : emitters) {
|
||||||
|
emitter.prepare(resultConsumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderType defaultLayer = ItemBlockRenderTypes.getChunkRenderType(state);
|
||||||
|
universalEmitter.prepare(defaultLayer);
|
||||||
|
model = universalEmitter.wrapModel(model);
|
||||||
|
|
||||||
|
poseStack.pushPose();
|
||||||
|
blockRenderer.tesselateBlock(level, model, state, BlockPos.ZERO, poseStack, universalEmitter, false, random, 42L, OverlayTexture.NO_OVERLAY);
|
||||||
|
poseStack.popPose();
|
||||||
|
|
||||||
|
universalEmitter.clear();
|
||||||
|
|
||||||
|
for (MeshEmitter emitter : emitters) {
|
||||||
|
emitter.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bufferBlock(BlockRenderDispatcher renderDispatcher, BlockAndTintGetter level, BlockState state, @Nullable PoseStack poseStack, ResultConsumer resultConsumer) {
|
||||||
|
if (state.getRenderShape() != RenderShape.MODEL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufferSingle(renderDispatcher.getModelRenderer(), level, renderDispatcher.getBlockModel(state), state, poseStack, resultConsumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bufferMultiBlock(BlockRenderDispatcher renderDispatcher, Iterator<BlockPos> posIterator, BlockAndTintGetter level, @Nullable PoseStack poseStack, boolean renderFluids, ResultConsumer resultConsumer) {
|
||||||
|
ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
|
||||||
|
if (poseStack == null) {
|
||||||
|
poseStack = objects.identityPoseStack;
|
||||||
|
}
|
||||||
|
RandomSource random = objects.random;
|
||||||
|
MeshEmitter[] emitters = objects.emitters;
|
||||||
|
Reference2ReferenceMap<RenderType, MeshEmitter> emitterMap = objects.emitterMap;
|
||||||
|
UniversalMeshEmitter universalEmitter = objects.universalEmitter;
|
||||||
|
TransformingVertexConsumer transformingWrapper = objects.transformingWrapper;
|
||||||
|
|
||||||
|
for (MeshEmitter emitter : emitters) {
|
||||||
|
emitter.prepare(resultConsumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelBlockRenderer blockRenderer = renderDispatcher.getModelRenderer();
|
||||||
|
ModelBlockRenderer.enableCaching();
|
||||||
|
|
||||||
|
while (posIterator.hasNext()) {
|
||||||
|
BlockPos pos = posIterator.next();
|
||||||
|
BlockState state = level.getBlockState(pos);
|
||||||
|
|
||||||
|
if (renderFluids) {
|
||||||
|
FluidState fluidState = state.getFluidState();
|
||||||
|
|
||||||
|
if (!fluidState.isEmpty()) {
|
||||||
|
RenderType renderType = ItemBlockRenderTypes.getRenderLayer(fluidState);
|
||||||
|
|
||||||
|
transformingWrapper.prepare(emitterMap.get(renderType).getBuffer(true), poseStack);
|
||||||
|
|
||||||
|
poseStack.pushPose();
|
||||||
|
poseStack.translate(pos.getX() - (pos.getX() & 0xF), pos.getY() - (pos.getY() & 0xF), pos.getZ() - (pos.getZ() & 0xF));
|
||||||
|
renderDispatcher.renderLiquid(pos, level, transformingWrapper, state, fluidState);
|
||||||
|
poseStack.popPose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.getRenderShape() == RenderShape.MODEL) {
|
||||||
|
long seed = state.getSeed(pos);
|
||||||
|
BakedModel model = renderDispatcher.getBlockModel(state);
|
||||||
|
|
||||||
|
RenderType defaultLayer = ItemBlockRenderTypes.getChunkRenderType(state);
|
||||||
|
universalEmitter.prepare(defaultLayer);
|
||||||
|
model = universalEmitter.wrapModel(model);
|
||||||
|
|
||||||
|
poseStack.pushPose();
|
||||||
|
poseStack.translate(pos.getX(), pos.getY(), pos.getZ());
|
||||||
|
blockRenderer.tesselateBlock(level, model, state, pos, poseStack, universalEmitter, true, random, seed, OverlayTexture.NO_OVERLAY);
|
||||||
|
poseStack.popPose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelBlockRenderer.clearCache();
|
||||||
|
transformingWrapper.clear();
|
||||||
|
universalEmitter.clear();
|
||||||
|
|
||||||
|
for (MeshEmitter emitter : emitters) {
|
||||||
|
emitter.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ResultConsumer {
|
||||||
|
void accept(RenderType renderType, boolean shaded, RenderedBuffer data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ThreadLocalObjects {
|
||||||
|
public final PoseStack identityPoseStack = new PoseStack();
|
||||||
|
public final RandomSource random = RandomSource.createNewThreadLocalInstance();
|
||||||
|
|
||||||
|
public final MeshEmitter[] emitters = new MeshEmitter[CHUNK_LAYER_AMOUNT];
|
||||||
|
public final Reference2ReferenceMap<RenderType, MeshEmitter> emitterMap = new Reference2ReferenceOpenHashMap<>();
|
||||||
|
public final UniversalMeshEmitter universalEmitter;
|
||||||
|
public final TransformingVertexConsumer transformingWrapper = new TransformingVertexConsumer();
|
||||||
|
|
||||||
|
{
|
||||||
|
for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) {
|
||||||
|
RenderType renderType = CHUNK_LAYERS[layerIndex];
|
||||||
|
MeshEmitter emitter = new MeshEmitter(renderType);
|
||||||
|
emitters[layerIndex] = emitter;
|
||||||
|
emitterMap.put(renderType, emitter);
|
||||||
|
}
|
||||||
|
universalEmitter = new UniversalMeshEmitter(emitterMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
package com.jozufozu.flywheel.lib.model.baked;
|
||||||
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.jozufozu.flywheel.api.material.Material;
|
||||||
|
import com.jozufozu.flywheel.api.model.Model;
|
||||||
|
import com.jozufozu.flywheel.api.vertex.VertexView;
|
||||||
|
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||||
|
import com.jozufozu.flywheel.lib.model.ModelUtil;
|
||||||
|
import com.jozufozu.flywheel.lib.model.SimpleMesh;
|
||||||
|
import com.jozufozu.flywheel.lib.model.SimpleModel;
|
||||||
|
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.resources.model.BakedModel;
|
||||||
|
import net.minecraft.world.level.BlockAndTintGetter;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
|
||||||
|
public final class FabricBakedModelBuilder extends BakedModelBuilder {
|
||||||
|
public FabricBakedModelBuilder(BakedModel bakedModel) {
|
||||||
|
super(bakedModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FabricBakedModelBuilder level(BlockAndTintGetter level) {
|
||||||
|
super.level(level);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FabricBakedModelBuilder blockState(BlockState blockState) {
|
||||||
|
super.blockState(blockState);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FabricBakedModelBuilder poseStack(PoseStack poseStack) {
|
||||||
|
super.poseStack(poseStack);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FabricBakedModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
|
||||||
|
super.materialFunc(materialFunc);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleModel build() {
|
||||||
|
if (level == null) {
|
||||||
|
level = VirtualEmptyBlockGetter.INSTANCE;
|
||||||
|
}
|
||||||
|
if (blockState == null) {
|
||||||
|
blockState = Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
if (materialFunc == null) {
|
||||||
|
materialFunc = ModelUtil::getMaterial;
|
||||||
|
}
|
||||||
|
|
||||||
|
var out = ImmutableList.<Model.ConfiguredMesh>builder();
|
||||||
|
|
||||||
|
BakedModelBufferer.bufferSingle(ModelUtil.VANILLA_RENDERER.getModelRenderer(), level, bakedModel, blockState, poseStack, (renderType, shaded, data) -> {
|
||||||
|
Material material = materialFunc.apply(renderType, shaded);
|
||||||
|
if (material != null) {
|
||||||
|
VertexView vertexView = new NoOverlayVertexView();
|
||||||
|
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
|
||||||
|
var mesh = new SimpleMesh(vertexView, meshData, "source=BakedModelBuilder," + "bakedModel=" + bakedModel + ",renderType=" + renderType + ",shaded=" + shaded);
|
||||||
|
out.add(new Model.ConfiguredMesh(material, mesh));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return new SimpleModel(out.build());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package com.jozufozu.flywheel.lib.model.baked;
|
||||||
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.jozufozu.flywheel.api.material.Material;
|
||||||
|
import com.jozufozu.flywheel.api.model.Model;
|
||||||
|
import com.jozufozu.flywheel.api.vertex.VertexView;
|
||||||
|
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||||
|
import com.jozufozu.flywheel.lib.model.ModelUtil;
|
||||||
|
import com.jozufozu.flywheel.lib.model.SimpleMesh;
|
||||||
|
import com.jozufozu.flywheel.lib.model.SimpleModel;
|
||||||
|
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.world.level.BlockAndTintGetter;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
|
||||||
|
public final class FabricBlockModelBuilder extends BlockModelBuilder {
|
||||||
|
public FabricBlockModelBuilder(BlockState state) {
|
||||||
|
super(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FabricBlockModelBuilder level(BlockAndTintGetter level) {
|
||||||
|
super.level(level);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FabricBlockModelBuilder poseStack(PoseStack poseStack) {
|
||||||
|
super.poseStack(poseStack);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FabricBlockModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
|
||||||
|
super.materialFunc(materialFunc);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleModel build() {
|
||||||
|
if (level == null) {
|
||||||
|
level = VirtualEmptyBlockGetter.INSTANCE;
|
||||||
|
}
|
||||||
|
if (materialFunc == null) {
|
||||||
|
materialFunc = ModelUtil::getMaterial;
|
||||||
|
}
|
||||||
|
|
||||||
|
var out = ImmutableList.<Model.ConfiguredMesh>builder();
|
||||||
|
|
||||||
|
BakedModelBufferer.bufferBlock(ModelUtil.VANILLA_RENDERER, level, state, poseStack, (renderType, shaded, data) -> {
|
||||||
|
Material material = materialFunc.apply(renderType, shaded);
|
||||||
|
if (material != null) {
|
||||||
|
VertexView vertexView = new NoOverlayVertexView();
|
||||||
|
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
|
||||||
|
var mesh = new SimpleMesh(vertexView, meshData, "source=BlockModelBuilder," + "blockState=" + state + ",renderType=" + renderType + ",shaded=" + shaded);
|
||||||
|
out.add(new Model.ConfiguredMesh(material, mesh));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return new SimpleModel(out.build());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package com.jozufozu.flywheel.lib.model.baked;
|
||||||
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.jozufozu.flywheel.api.material.Material;
|
||||||
|
import com.jozufozu.flywheel.api.model.Model;
|
||||||
|
import com.jozufozu.flywheel.api.vertex.VertexView;
|
||||||
|
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||||
|
import com.jozufozu.flywheel.lib.model.ModelUtil;
|
||||||
|
import com.jozufozu.flywheel.lib.model.SimpleMesh;
|
||||||
|
import com.jozufozu.flywheel.lib.model.SimpleModel;
|
||||||
|
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.level.BlockAndTintGetter;
|
||||||
|
|
||||||
|
public final class FabricMultiBlockModelBuilder extends MultiBlockModelBuilder {
|
||||||
|
public FabricMultiBlockModelBuilder(BlockAndTintGetter level, Iterable<BlockPos> positions) {
|
||||||
|
super(level, positions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FabricMultiBlockModelBuilder poseStack(PoseStack poseStack) {
|
||||||
|
super.poseStack(poseStack);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FabricMultiBlockModelBuilder enableFluidRendering() {
|
||||||
|
super.enableFluidRendering();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FabricMultiBlockModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
|
||||||
|
super.materialFunc(materialFunc);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleModel build() {
|
||||||
|
if (materialFunc == null) {
|
||||||
|
materialFunc = ModelUtil::getMaterial;
|
||||||
|
}
|
||||||
|
|
||||||
|
var out = ImmutableList.<Model.ConfiguredMesh>builder();
|
||||||
|
|
||||||
|
BakedModelBufferer.bufferMultiBlock(ModelUtil.VANILLA_RENDERER, positions.iterator(), level, poseStack, renderFluids, (renderType, shaded, data) -> {
|
||||||
|
Material material = materialFunc.apply(renderType, shaded);
|
||||||
|
if (material != null) {
|
||||||
|
VertexView vertexView = new NoOverlayVertexView();
|
||||||
|
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
|
||||||
|
var mesh = new SimpleMesh(vertexView, meshData, "source=MultiBlockModelBuilder," + "renderType=" + renderType + ",shaded=" + shaded);
|
||||||
|
out.add(new Model.ConfiguredMesh(material, mesh));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return new SimpleModel(out.build());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package com.jozufozu.flywheel.lib.model.baked;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.UnknownNullability;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||||
|
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
|
||||||
|
class MeshEmitter {
|
||||||
|
private final RenderType renderType;
|
||||||
|
private final BufferBuilder bufferBuilder;
|
||||||
|
|
||||||
|
private BakedModelBufferer.@UnknownNullability ResultConsumer resultConsumer;
|
||||||
|
private boolean currentShade;
|
||||||
|
|
||||||
|
MeshEmitter(RenderType renderType) {
|
||||||
|
this.renderType = renderType;
|
||||||
|
this.bufferBuilder = new BufferBuilder(renderType.bufferSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void prepare(BakedModelBufferer.ResultConsumer resultConsumer) {
|
||||||
|
this.resultConsumer = resultConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void end() {
|
||||||
|
if (bufferBuilder.building()) {
|
||||||
|
emit();
|
||||||
|
}
|
||||||
|
resultConsumer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferBuilder getBuffer(boolean shade) {
|
||||||
|
prepareForGeometry(shade);
|
||||||
|
return bufferBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepareForGeometry(boolean shade) {
|
||||||
|
if (!bufferBuilder.building()) {
|
||||||
|
bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
||||||
|
} else if (shade != currentShade) {
|
||||||
|
emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
currentShade = shade;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emit() {
|
||||||
|
var renderedBuffer = bufferBuilder.endOrDiscardIfEmpty();
|
||||||
|
|
||||||
|
if (renderedBuffer != null) {
|
||||||
|
resultConsumer.accept(renderType, currentShade, renderedBuffer);
|
||||||
|
renderedBuffer.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,146 @@
|
||||||
|
package com.jozufozu.flywheel.lib.model.baked;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.annotations.UnknownNullability;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap;
|
||||||
|
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.model.ForwardingBakedModel;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||||
|
import net.minecraft.client.resources.model.BakedModel;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
import net.minecraft.world.level.BlockAndTintGetter;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
|
||||||
|
class UniversalMeshEmitter implements VertexConsumer {
|
||||||
|
private final Reference2ReferenceMap<RenderType, MeshEmitter> emitterMap;
|
||||||
|
private final WrapperModel wrapperModel = new WrapperModel();
|
||||||
|
|
||||||
|
@UnknownNullability
|
||||||
|
private RenderType defaultLayer;
|
||||||
|
@UnknownNullability
|
||||||
|
private BufferBuilder currentDelegate;
|
||||||
|
|
||||||
|
UniversalMeshEmitter(Reference2ReferenceMap<RenderType, MeshEmitter> emitterMap) {
|
||||||
|
this.emitterMap = emitterMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void prepare(RenderType defaultLayer) {
|
||||||
|
this.defaultLayer = defaultLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
wrapperModel.setWrapped(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BakedModel wrapModel(BakedModel model) {
|
||||||
|
wrapperModel.setWrapped(model);
|
||||||
|
return wrapperModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareForGeometry(RenderMaterial material) {
|
||||||
|
BlendMode blendMode = material.blendMode();
|
||||||
|
RenderType layer = blendMode == BlendMode.DEFAULT ? defaultLayer : blendMode.blockRenderLayer;
|
||||||
|
boolean shade = !material.disableDiffuse();
|
||||||
|
currentDelegate = emitterMap.get(layer).getBuffer(shade);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VertexConsumer vertex(double x, double y, double z) {
|
||||||
|
currentDelegate.vertex(x, y, z);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VertexConsumer color(int red, int green, int blue, int alpha) {
|
||||||
|
currentDelegate.color(red, green, blue, alpha);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VertexConsumer uv(float u, float v) {
|
||||||
|
currentDelegate.uv(u, v);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VertexConsumer overlayCoords(int u, int v) {
|
||||||
|
currentDelegate.overlayCoords(u, v);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VertexConsumer uv2(int u, int v) {
|
||||||
|
currentDelegate.uv2(u, v);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VertexConsumer normal(float x, float y, float z) {
|
||||||
|
currentDelegate.normal(x, y, z);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endVertex() {
|
||||||
|
currentDelegate.endVertex();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void defaultColor(int red, int green, int blue, int alpha) {
|
||||||
|
currentDelegate.defaultColor(red, green, blue, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unsetDefaultColor() {
|
||||||
|
currentDelegate.unsetDefaultColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void vertex(float x, float y, float z, float red, float green, float blue, float alpha, float u, float v, int overlay, int light, float normalX, float normalY, float normalZ) {
|
||||||
|
currentDelegate.vertex(x, y, z, red, green, blue, alpha, u, v, overlay, light, normalX, normalY, normalZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putBulkData(PoseStack.Pose pose, BakedQuad quad, float red, float green, float blue, int light, int overlay) {
|
||||||
|
currentDelegate.putBulkData(pose, quad, red, green, blue, light, overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putBulkData(PoseStack.Pose pose, BakedQuad quad, float[] brightnesses, float red, float green, float blue, int[] lights, int overlay, boolean readExistingColor) {
|
||||||
|
currentDelegate.putBulkData(pose, quad, brightnesses, red, green, blue, lights, overlay, readExistingColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class WrapperModel extends ForwardingBakedModel {
|
||||||
|
private final RenderContext.QuadTransform quadTransform = quad -> {
|
||||||
|
UniversalMeshEmitter.this.prepareForGeometry(quad.material());
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
public void setWrapped(@Nullable BakedModel wrapped) {
|
||||||
|
this.wrapped = wrapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isVanillaAdapter() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void emitBlockQuads(BlockAndTintGetter level, BlockState state, BlockPos pos, Supplier<RandomSource> randomSupplier, RenderContext context) {
|
||||||
|
context.pushTransform(quadTransform);
|
||||||
|
super.emitBlockQuads(level, state, pos, randomSupplier, context);
|
||||||
|
context.popTransform();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,9 @@ import org.jetbrains.annotations.Nullable;
|
||||||
import com.jozufozu.flywheel.lib.internal.FlwLibXplat;
|
import com.jozufozu.flywheel.lib.internal.FlwLibXplat;
|
||||||
import com.jozufozu.flywheel.lib.model.baked.BakedModelBuilder;
|
import com.jozufozu.flywheel.lib.model.baked.BakedModelBuilder;
|
||||||
import com.jozufozu.flywheel.lib.model.baked.BlockModelBuilder;
|
import com.jozufozu.flywheel.lib.model.baked.BlockModelBuilder;
|
||||||
|
import com.jozufozu.flywheel.lib.model.baked.FabricBakedModelBuilder;
|
||||||
|
import com.jozufozu.flywheel.lib.model.baked.FabricBlockModelBuilder;
|
||||||
|
import com.jozufozu.flywheel.lib.model.baked.FabricMultiBlockModelBuilder;
|
||||||
import com.jozufozu.flywheel.lib.model.baked.MultiBlockModelBuilder;
|
import com.jozufozu.flywheel.lib.model.baked.MultiBlockModelBuilder;
|
||||||
import com.jozufozu.flywheel.lib.util.ShadersModHandler;
|
import com.jozufozu.flywheel.lib.util.ShadersModHandler;
|
||||||
|
|
||||||
|
@ -25,17 +28,17 @@ public class FlwLibXplatImpl implements FlwLibXplat {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BakedModelBuilder createBakedModelBuilder(BakedModel bakedModel) {
|
public BakedModelBuilder createBakedModelBuilder(BakedModel bakedModel) {
|
||||||
return null;
|
return new FabricBakedModelBuilder(bakedModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockModelBuilder createBlockModelBuilder(BlockState state) {
|
public BlockModelBuilder createBlockModelBuilder(BlockState state) {
|
||||||
return null;
|
return new FabricBlockModelBuilder(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MultiBlockModelBuilder createMultiBlockModelBuilder(BlockAndTintGetter level, Iterable<BlockPos> positions) {
|
public MultiBlockModelBuilder createMultiBlockModelBuilder(BlockAndTintGetter level, Iterable<BlockPos> positions) {
|
||||||
return null;
|
return new FabricMultiBlockModelBuilder(level, positions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -5,7 +5,6 @@ import java.util.function.Function;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
|
||||||
import com.mojang.blaze3d.vertex.BufferBuilder.RenderedBuffer;
|
import com.mojang.blaze3d.vertex.BufferBuilder.RenderedBuffer;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
|
||||||
|
@ -33,13 +32,13 @@ final class BakedModelBufferer {
|
||||||
private BakedModelBufferer() {
|
private BakedModelBufferer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void bufferSingle(ModelBlockRenderer blockRenderer, BlockAndTintGetter level, BakedModel model, BlockState state, @Nullable PoseStack poseStack, ModelData modelData, MeshEmitter.ResultConsumer resultConsumer) {
|
public static void bufferSingle(ModelBlockRenderer blockRenderer, BlockAndTintGetter level, BakedModel model, BlockState state, @Nullable PoseStack poseStack, ModelData modelData, ResultConsumer resultConsumer) {
|
||||||
ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
|
ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
|
||||||
if (poseStack == null) {
|
if (poseStack == null) {
|
||||||
poseStack = objects.identityPoseStack;
|
poseStack = objects.identityPoseStack;
|
||||||
}
|
}
|
||||||
RandomSource random = objects.random;
|
RandomSource random = objects.random;
|
||||||
var consumers = objects.emitters;
|
MeshEmitter[] emitters = objects.emitters;
|
||||||
|
|
||||||
modelData = model.getModelData(level, BlockPos.ZERO, state, modelData);
|
modelData = model.getModelData(level, BlockPos.ZERO, state, modelData);
|
||||||
random.setSeed(42L);
|
random.setSeed(42L);
|
||||||
|
@ -47,19 +46,19 @@ final class BakedModelBufferer {
|
||||||
|
|
||||||
for (RenderType renderType : renderTypes) {
|
for (RenderType renderType : renderTypes) {
|
||||||
int layerIndex = renderType.getChunkLayerId();
|
int layerIndex = renderType.getChunkLayerId();
|
||||||
var consumer = consumers[layerIndex];
|
MeshEmitter emitter = emitters[layerIndex];
|
||||||
|
|
||||||
consumer.begin(resultConsumer);
|
emitter.prepare(resultConsumer);
|
||||||
|
|
||||||
poseStack.pushPose();
|
poseStack.pushPose();
|
||||||
blockRenderer.tesselateBlock(level, model, state, BlockPos.ZERO, poseStack, consumer, false, random, 42L, OverlayTexture.NO_OVERLAY, modelData, renderType);
|
blockRenderer.tesselateBlock(level, model, state, BlockPos.ZERO, poseStack, emitter, false, random, 42L, OverlayTexture.NO_OVERLAY, modelData, renderType);
|
||||||
poseStack.popPose();
|
poseStack.popPose();
|
||||||
|
|
||||||
consumer.end();
|
emitter.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void bufferBlock(BlockRenderDispatcher renderDispatcher, BlockAndTintGetter level, BlockState state, @Nullable PoseStack poseStack, ModelData modelData, MeshEmitter.ResultConsumer resultConsumer) {
|
public static void bufferBlock(BlockRenderDispatcher renderDispatcher, BlockAndTintGetter level, BlockState state, @Nullable PoseStack poseStack, ModelData modelData, ResultConsumer resultConsumer) {
|
||||||
if (state.getRenderShape() != RenderShape.MODEL) {
|
if (state.getRenderShape() != RenderShape.MODEL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -67,18 +66,17 @@ final class BakedModelBufferer {
|
||||||
bufferSingle(renderDispatcher.getModelRenderer(), level, renderDispatcher.getBlockModel(state), state, poseStack, modelData, resultConsumer);
|
bufferSingle(renderDispatcher.getModelRenderer(), level, renderDispatcher.getBlockModel(state), state, poseStack, modelData, resultConsumer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void bufferMultiBlock(BlockRenderDispatcher renderDispatcher, Iterator<BlockPos> posIterator, BlockAndTintGetter level, @Nullable PoseStack poseStack, Function<BlockPos, ModelData> modelDataLookup, boolean renderFluids, MeshEmitter.ResultConsumer resultConsumer) {
|
public static void bufferMultiBlock(BlockRenderDispatcher renderDispatcher, Iterator<BlockPos> posIterator, BlockAndTintGetter level, @Nullable PoseStack poseStack, Function<BlockPos, ModelData> modelDataLookup, boolean renderFluids, ResultConsumer resultConsumer) {
|
||||||
ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
|
ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
|
||||||
if (poseStack == null) {
|
if (poseStack == null) {
|
||||||
poseStack = objects.identityPoseStack;
|
poseStack = objects.identityPoseStack;
|
||||||
}
|
}
|
||||||
RandomSource random = objects.random;
|
RandomSource random = objects.random;
|
||||||
|
MeshEmitter[] emitters = objects.emitters;
|
||||||
TransformingVertexConsumer transformingWrapper = objects.transformingWrapper;
|
TransformingVertexConsumer transformingWrapper = objects.transformingWrapper;
|
||||||
|
|
||||||
var emitters = objects.emitters;
|
for (MeshEmitter emitter : emitters) {
|
||||||
|
emitter.prepare(resultConsumer);
|
||||||
for (var emitter : emitters) {
|
|
||||||
emitter.begin(resultConsumer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelBlockRenderer blockRenderer = renderDispatcher.getModelRenderer();
|
ModelBlockRenderer blockRenderer = renderDispatcher.getModelRenderer();
|
||||||
|
@ -92,10 +90,10 @@ final class BakedModelBufferer {
|
||||||
FluidState fluidState = state.getFluidState();
|
FluidState fluidState = state.getFluidState();
|
||||||
|
|
||||||
if (!fluidState.isEmpty()) {
|
if (!fluidState.isEmpty()) {
|
||||||
RenderType layer = ItemBlockRenderTypes.getRenderLayer(fluidState);
|
RenderType renderType = ItemBlockRenderTypes.getRenderLayer(fluidState);
|
||||||
int layerIndex = layer.getChunkLayerId();
|
int layerIndex = renderType.getChunkLayerId();
|
||||||
|
|
||||||
transformingWrapper.prepare(emitters[layerIndex], poseStack);
|
transformingWrapper.prepare(emitters[layerIndex].unwrap(true), poseStack);
|
||||||
|
|
||||||
poseStack.pushPose();
|
poseStack.pushPose();
|
||||||
poseStack.translate(pos.getX() - (pos.getX() & 0xF), pos.getY() - (pos.getY() & 0xF), pos.getZ() - (pos.getZ() & 0xF));
|
poseStack.translate(pos.getX() - (pos.getX() & 0xF), pos.getY() - (pos.getY() & 0xF), pos.getZ() - (pos.getZ() & 0xF));
|
||||||
|
@ -124,12 +122,11 @@ final class BakedModelBufferer {
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelBlockRenderer.clearCache();
|
ModelBlockRenderer.clearCache();
|
||||||
|
transformingWrapper.clear();
|
||||||
|
|
||||||
for (var emitter : emitters) {
|
for (MeshEmitter emitter : emitters) {
|
||||||
emitter.end();
|
emitter.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
transformingWrapper.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ResultConsumer {
|
public interface ResultConsumer {
|
||||||
|
@ -140,15 +137,13 @@ final class BakedModelBufferer {
|
||||||
public final PoseStack identityPoseStack = new PoseStack();
|
public final PoseStack identityPoseStack = new PoseStack();
|
||||||
public final RandomSource random = RandomSource.createNewThreadLocalInstance();
|
public final RandomSource random = RandomSource.createNewThreadLocalInstance();
|
||||||
|
|
||||||
|
public final MeshEmitter[] emitters = new MeshEmitter[CHUNK_LAYER_AMOUNT];
|
||||||
public final TransformingVertexConsumer transformingWrapper = new TransformingVertexConsumer();
|
public final TransformingVertexConsumer transformingWrapper = new TransformingVertexConsumer();
|
||||||
|
|
||||||
public final ForgeMeshEmitter[] emitters = new ForgeMeshEmitter[CHUNK_LAYER_AMOUNT];
|
|
||||||
|
|
||||||
{
|
{
|
||||||
for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) {
|
for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) {
|
||||||
var renderType = CHUNK_LAYERS[layerIndex];
|
RenderType renderType = CHUNK_LAYERS[layerIndex];
|
||||||
var buffer = new BufferBuilder(renderType.bufferSize());
|
emitters[layerIndex] = new MeshEmitter(renderType);
|
||||||
emitters[layerIndex] = new ForgeMeshEmitter(buffer, renderType);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package com.jozufozu.flywheel.lib.model.baked;
|
package com.jozufozu.flywheel.lib.model.baked;
|
||||||
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
@ -10,14 +12,17 @@ import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||||
import com.jozufozu.flywheel.lib.model.ModelUtil;
|
import com.jozufozu.flywheel.lib.model.ModelUtil;
|
||||||
import com.jozufozu.flywheel.lib.model.SimpleMesh;
|
import com.jozufozu.flywheel.lib.model.SimpleMesh;
|
||||||
import com.jozufozu.flywheel.lib.model.SimpleModel;
|
import com.jozufozu.flywheel.lib.model.SimpleModel;
|
||||||
import com.jozufozu.flywheel.lib.model.baked.MeshEmitter.ResultConsumer;
|
|
||||||
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
|
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
import net.minecraft.client.resources.model.BakedModel;
|
||||||
|
import net.minecraft.world.level.BlockAndTintGetter;
|
||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraftforge.client.model.data.ModelData;
|
import net.minecraftforge.client.model.data.ModelData;
|
||||||
|
|
||||||
public class ForgeBakedModelBuilder extends BakedModelBuilder {
|
public final class ForgeBakedModelBuilder extends BakedModelBuilder {
|
||||||
@Nullable
|
@Nullable
|
||||||
private ModelData modelData;
|
private ModelData modelData;
|
||||||
|
|
||||||
|
@ -25,11 +30,36 @@ public class ForgeBakedModelBuilder extends BakedModelBuilder {
|
||||||
super(bakedModel);
|
super(bakedModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ForgeBakedModelBuilder level(BlockAndTintGetter level) {
|
||||||
|
super.level(level);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ForgeBakedModelBuilder blockState(BlockState blockState) {
|
||||||
|
super.blockState(blockState);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ForgeBakedModelBuilder poseStack(PoseStack poseStack) {
|
||||||
|
super.poseStack(poseStack);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ForgeBakedModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
|
||||||
|
super.materialFunc(materialFunc);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public ForgeBakedModelBuilder modelData(ModelData modelData) {
|
public ForgeBakedModelBuilder modelData(ModelData modelData) {
|
||||||
this.modelData = modelData;
|
this.modelData = modelData;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public SimpleModel build() {
|
public SimpleModel build() {
|
||||||
if (level == null) {
|
if (level == null) {
|
||||||
level = VirtualEmptyBlockGetter.INSTANCE;
|
level = VirtualEmptyBlockGetter.INSTANCE;
|
||||||
|
@ -37,16 +67,16 @@ public class ForgeBakedModelBuilder extends BakedModelBuilder {
|
||||||
if (blockState == null) {
|
if (blockState == null) {
|
||||||
blockState = Blocks.AIR.defaultBlockState();
|
blockState = Blocks.AIR.defaultBlockState();
|
||||||
}
|
}
|
||||||
if (modelData == null) {
|
|
||||||
modelData = ModelData.EMPTY;
|
|
||||||
}
|
|
||||||
if (materialFunc == null) {
|
if (materialFunc == null) {
|
||||||
materialFunc = ModelUtil::getMaterial;
|
materialFunc = ModelUtil::getMaterial;
|
||||||
}
|
}
|
||||||
|
if (modelData == null) {
|
||||||
|
modelData = ModelData.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
var out = ImmutableList.<Model.ConfiguredMesh>builder();
|
var out = ImmutableList.<Model.ConfiguredMesh>builder();
|
||||||
|
|
||||||
ResultConsumer resultConsumer = (renderType, shaded, data) -> {
|
BakedModelBufferer.bufferSingle(ModelUtil.VANILLA_RENDERER.getModelRenderer(), level, bakedModel, blockState, poseStack, modelData, (renderType, shaded, data) -> {
|
||||||
Material material = materialFunc.apply(renderType, shaded);
|
Material material = materialFunc.apply(renderType, shaded);
|
||||||
if (material != null) {
|
if (material != null) {
|
||||||
VertexView vertexView = new NoOverlayVertexView();
|
VertexView vertexView = new NoOverlayVertexView();
|
||||||
|
@ -54,8 +84,7 @@ public class ForgeBakedModelBuilder extends BakedModelBuilder {
|
||||||
var mesh = new SimpleMesh(vertexView, meshData, "source=BakedModelBuilder," + "bakedModel=" + bakedModel + ",renderType=" + renderType + ",shaded=" + shaded);
|
var mesh = new SimpleMesh(vertexView, meshData, "source=BakedModelBuilder," + "bakedModel=" + bakedModel + ",renderType=" + renderType + ",shaded=" + shaded);
|
||||||
out.add(new Model.ConfiguredMesh(material, mesh));
|
out.add(new Model.ConfiguredMesh(material, mesh));
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
BakedModelBufferer.bufferSingle(ModelUtil.VANILLA_RENDERER.getModelRenderer(), level, bakedModel, blockState, poseStack, modelData, resultConsumer);
|
|
||||||
|
|
||||||
return new SimpleModel(out.build());
|
return new SimpleModel(out.build());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package com.jozufozu.flywheel.lib.model.baked;
|
package com.jozufozu.flywheel.lib.model.baked;
|
||||||
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
@ -10,13 +12,15 @@ import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||||
import com.jozufozu.flywheel.lib.model.ModelUtil;
|
import com.jozufozu.flywheel.lib.model.ModelUtil;
|
||||||
import com.jozufozu.flywheel.lib.model.SimpleMesh;
|
import com.jozufozu.flywheel.lib.model.SimpleMesh;
|
||||||
import com.jozufozu.flywheel.lib.model.SimpleModel;
|
import com.jozufozu.flywheel.lib.model.SimpleModel;
|
||||||
import com.jozufozu.flywheel.lib.model.baked.MeshEmitter.ResultConsumer;
|
|
||||||
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
|
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.world.level.BlockAndTintGetter;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraftforge.client.model.data.ModelData;
|
import net.minecraftforge.client.model.data.ModelData;
|
||||||
|
|
||||||
public class ForgeBlockModelBuilder extends BlockModelBuilder {
|
public final class ForgeBlockModelBuilder extends BlockModelBuilder {
|
||||||
@Nullable
|
@Nullable
|
||||||
private ModelData modelData;
|
private ModelData modelData;
|
||||||
|
|
||||||
|
@ -24,25 +28,44 @@ public class ForgeBlockModelBuilder extends BlockModelBuilder {
|
||||||
super(state);
|
super(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ForgeBlockModelBuilder level(BlockAndTintGetter level) {
|
||||||
|
super.level(level);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ForgeBlockModelBuilder poseStack(PoseStack poseStack) {
|
||||||
|
super.poseStack(poseStack);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ForgeBlockModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
|
||||||
|
super.materialFunc(materialFunc);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public ForgeBlockModelBuilder modelData(ModelData modelData) {
|
public ForgeBlockModelBuilder modelData(ModelData modelData) {
|
||||||
this.modelData = modelData;
|
this.modelData = modelData;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public SimpleModel build() {
|
public SimpleModel build() {
|
||||||
if (level == null) {
|
if (level == null) {
|
||||||
level = VirtualEmptyBlockGetter.INSTANCE;
|
level = VirtualEmptyBlockGetter.INSTANCE;
|
||||||
}
|
}
|
||||||
if (modelData == null) {
|
|
||||||
modelData = ModelData.EMPTY;
|
|
||||||
}
|
|
||||||
if (materialFunc == null) {
|
if (materialFunc == null) {
|
||||||
materialFunc = ModelUtil::getMaterial;
|
materialFunc = ModelUtil::getMaterial;
|
||||||
}
|
}
|
||||||
|
if (modelData == null) {
|
||||||
|
modelData = ModelData.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
var out = ImmutableList.<Model.ConfiguredMesh>builder();
|
var out = ImmutableList.<Model.ConfiguredMesh>builder();
|
||||||
|
|
||||||
ResultConsumer resultConsumer = (renderType, shaded, data) -> {
|
BakedModelBufferer.bufferBlock(ModelUtil.VANILLA_RENDERER, level, state, poseStack, modelData, (renderType, shaded, data) -> {
|
||||||
Material material = materialFunc.apply(renderType, shaded);
|
Material material = materialFunc.apply(renderType, shaded);
|
||||||
if (material != null) {
|
if (material != null) {
|
||||||
VertexView vertexView = new NoOverlayVertexView();
|
VertexView vertexView = new NoOverlayVertexView();
|
||||||
|
@ -50,8 +73,7 @@ public class ForgeBlockModelBuilder extends BlockModelBuilder {
|
||||||
var mesh = new SimpleMesh(vertexView, meshData, "source=BlockModelBuilder," + "blockState=" + state + ",renderType=" + renderType + ",shaded=" + shaded);
|
var mesh = new SimpleMesh(vertexView, meshData, "source=BlockModelBuilder," + "blockState=" + state + ",renderType=" + renderType + ",shaded=" + shaded);
|
||||||
out.add(new Model.ConfiguredMesh(material, mesh));
|
out.add(new Model.ConfiguredMesh(material, mesh));
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
BakedModelBufferer.bufferBlock(ModelUtil.VANILLA_RENDERER, level, state, poseStack, modelData, resultConsumer);
|
|
||||||
|
|
||||||
return new SimpleModel(out.build());
|
return new SimpleModel(out.build());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
package com.jozufozu.flywheel.lib.model.baked;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
|
||||||
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
|
||||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
|
||||||
|
|
||||||
class ForgeMeshEmitter extends MeshEmitter {
|
|
||||||
ForgeMeshEmitter(BufferBuilder bufferBuilder, RenderType renderType) {
|
|
||||||
super(bufferBuilder, renderType);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forge has another putBulkData that we need to override
|
|
||||||
@Override
|
|
||||||
public void putBulkData(PoseStack.Pose matrixEntry, BakedQuad quad, float[] baseBrightness, float red, float green, float blue, float alpha, int[] lightmapCoords, int overlayCoords, boolean readExistingColor) {
|
|
||||||
observeQuadAndEmitIfNecessary(quad);
|
|
||||||
|
|
||||||
bufferBuilder.putBulkData(matrixEntry, quad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.jozufozu.flywheel.lib.model.baked;
|
package com.jozufozu.flywheel.lib.model.baked;
|
||||||
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
@ -12,14 +13,15 @@ import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||||
import com.jozufozu.flywheel.lib.model.ModelUtil;
|
import com.jozufozu.flywheel.lib.model.ModelUtil;
|
||||||
import com.jozufozu.flywheel.lib.model.SimpleMesh;
|
import com.jozufozu.flywheel.lib.model.SimpleMesh;
|
||||||
import com.jozufozu.flywheel.lib.model.SimpleModel;
|
import com.jozufozu.flywheel.lib.model.SimpleModel;
|
||||||
import com.jozufozu.flywheel.lib.model.baked.MeshEmitter.ResultConsumer;
|
|
||||||
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
|
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.level.BlockAndTintGetter;
|
import net.minecraft.world.level.BlockAndTintGetter;
|
||||||
import net.minecraftforge.client.model.data.ModelData;
|
import net.minecraftforge.client.model.data.ModelData;
|
||||||
|
|
||||||
public class ForgeMultiBlockModelBuilder extends MultiBlockModelBuilder {
|
public final class ForgeMultiBlockModelBuilder extends MultiBlockModelBuilder {
|
||||||
@Nullable
|
@Nullable
|
||||||
private Function<BlockPos, ModelData> modelDataLookup;
|
private Function<BlockPos, ModelData> modelDataLookup;
|
||||||
|
|
||||||
|
@ -27,22 +29,41 @@ public class ForgeMultiBlockModelBuilder extends MultiBlockModelBuilder {
|
||||||
super(level, positions);
|
super(level, positions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ForgeMultiBlockModelBuilder poseStack(PoseStack poseStack) {
|
||||||
|
super.poseStack(poseStack);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ForgeMultiBlockModelBuilder enableFluidRendering() {
|
||||||
|
super.enableFluidRendering();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ForgeMultiBlockModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
|
||||||
|
super.materialFunc(materialFunc);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public ForgeMultiBlockModelBuilder modelDataLookup(Function<BlockPos, ModelData> modelDataLookup) {
|
public ForgeMultiBlockModelBuilder modelDataLookup(Function<BlockPos, ModelData> modelDataLookup) {
|
||||||
this.modelDataLookup = modelDataLookup;
|
this.modelDataLookup = modelDataLookup;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public SimpleModel build() {
|
public SimpleModel build() {
|
||||||
if (modelDataLookup == null) {
|
|
||||||
modelDataLookup = pos -> ModelData.EMPTY;
|
|
||||||
}
|
|
||||||
if (materialFunc == null) {
|
if (materialFunc == null) {
|
||||||
materialFunc = ModelUtil::getMaterial;
|
materialFunc = ModelUtil::getMaterial;
|
||||||
}
|
}
|
||||||
|
if (modelDataLookup == null) {
|
||||||
|
modelDataLookup = pos -> ModelData.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
var out = ImmutableList.<Model.ConfiguredMesh>builder();
|
var out = ImmutableList.<Model.ConfiguredMesh>builder();
|
||||||
|
|
||||||
ResultConsumer resultConsumer = (renderType, shaded, data) -> {
|
BakedModelBufferer.bufferMultiBlock(ModelUtil.VANILLA_RENDERER, positions.iterator(), level, poseStack, modelDataLookup, renderFluids, (renderType, shaded, data) -> {
|
||||||
Material material = materialFunc.apply(renderType, shaded);
|
Material material = materialFunc.apply(renderType, shaded);
|
||||||
if (material != null) {
|
if (material != null) {
|
||||||
VertexView vertexView = new NoOverlayVertexView();
|
VertexView vertexView = new NoOverlayVertexView();
|
||||||
|
@ -50,8 +71,7 @@ public class ForgeMultiBlockModelBuilder extends MultiBlockModelBuilder {
|
||||||
var mesh = new SimpleMesh(vertexView, meshData, "source=MultiBlockModelBuilder," + "renderType=" + renderType + ",shaded=" + shaded);
|
var mesh = new SimpleMesh(vertexView, meshData, "source=MultiBlockModelBuilder," + "renderType=" + renderType + ",shaded=" + shaded);
|
||||||
out.add(new Model.ConfiguredMesh(material, mesh));
|
out.add(new Model.ConfiguredMesh(material, mesh));
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
BakedModelBufferer.bufferMultiBlock(ModelUtil.VANILLA_RENDERER, positions.iterator(), level, poseStack, modelDataLookup, renderFluids, resultConsumer);
|
|
||||||
|
|
||||||
return new SimpleModel(out.build());
|
return new SimpleModel(out.build());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
package com.jozufozu.flywheel.lib.model.baked;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.UnknownNullability;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||||
|
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||||
|
|
||||||
|
class MeshEmitter implements VertexConsumer {
|
||||||
|
private final RenderType renderType;
|
||||||
|
private final BufferBuilder bufferBuilder;
|
||||||
|
|
||||||
|
private BakedModelBufferer.@UnknownNullability ResultConsumer resultConsumer;
|
||||||
|
private boolean currentShade;
|
||||||
|
|
||||||
|
MeshEmitter(RenderType renderType) {
|
||||||
|
this.renderType = renderType;
|
||||||
|
this.bufferBuilder = new BufferBuilder(renderType.bufferSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void prepare(BakedModelBufferer.ResultConsumer resultConsumer) {
|
||||||
|
this.resultConsumer = resultConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void end() {
|
||||||
|
if (bufferBuilder.building()) {
|
||||||
|
emit();
|
||||||
|
}
|
||||||
|
resultConsumer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferBuilder unwrap(boolean shade) {
|
||||||
|
prepareForGeometry(shade);
|
||||||
|
return bufferBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareForGeometry(boolean shade) {
|
||||||
|
if (!bufferBuilder.building()) {
|
||||||
|
bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
||||||
|
} else if (shade != currentShade) {
|
||||||
|
emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
currentShade = shade;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareForGeometry(BakedQuad quad) {
|
||||||
|
prepareForGeometry(quad.isShade());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void emit() {
|
||||||
|
var renderedBuffer = bufferBuilder.endOrDiscardIfEmpty();
|
||||||
|
|
||||||
|
if (renderedBuffer != null) {
|
||||||
|
resultConsumer.accept(renderType, currentShade, renderedBuffer);
|
||||||
|
renderedBuffer.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putBulkData(PoseStack.Pose pose, BakedQuad quad, float red, float green, float blue, int light, int overlay) {
|
||||||
|
prepareForGeometry(quad);
|
||||||
|
bufferBuilder.putBulkData(pose, quad, red, green, blue, light, overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putBulkData(PoseStack.Pose pose, BakedQuad quad, float red, float green, float blue, float alpha, int light, int overlay, boolean readExistingColor) {
|
||||||
|
prepareForGeometry(quad);
|
||||||
|
bufferBuilder.putBulkData(pose, quad, red, green, blue, alpha, light, overlay, readExistingColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putBulkData(PoseStack.Pose pose, BakedQuad quad, float[] brightnesses, float red, float green, float blue, int[] lights, int overlay, boolean readExistingColor) {
|
||||||
|
prepareForGeometry(quad);
|
||||||
|
bufferBuilder.putBulkData(pose, quad, brightnesses, red, green, blue, lights, overlay, readExistingColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putBulkData(PoseStack.Pose pose, BakedQuad quad, float[] brightnesses, float red, float green, float blue, float alpha, int[] lights, int overlay, boolean readExistingColor) {
|
||||||
|
prepareForGeometry(quad);
|
||||||
|
bufferBuilder.putBulkData(pose, quad, brightnesses, red, green, blue, alpha, lights, overlay, readExistingColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VertexConsumer vertex(double x, double y, double z) {
|
||||||
|
throw new UnsupportedOperationException("MeshEmitter only supports putBulkData!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VertexConsumer color(int red, int green, int blue, int alpha) {
|
||||||
|
throw new UnsupportedOperationException("MeshEmitter only supports putBulkData!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VertexConsumer uv(float u, float v) {
|
||||||
|
throw new UnsupportedOperationException("MeshEmitter only supports putBulkData!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VertexConsumer overlayCoords(int u, int v) {
|
||||||
|
throw new UnsupportedOperationException("MeshEmitter only supports putBulkData!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VertexConsumer uv2(int u, int v) {
|
||||||
|
throw new UnsupportedOperationException("MeshEmitter only supports putBulkData!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VertexConsumer normal(float x, float y, float z) {
|
||||||
|
throw new UnsupportedOperationException("MeshEmitter only supports putBulkData!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endVertex() {
|
||||||
|
throw new UnsupportedOperationException("MeshEmitter only supports putBulkData!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void defaultColor(int red, int green, int blue, int alpha) {
|
||||||
|
throw new UnsupportedOperationException("MeshEmitter only supports putBulkData!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unsetDefaultColor() {
|
||||||
|
throw new UnsupportedOperationException("MeshEmitter only supports putBulkData!");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue