mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-11-14 22:43:56 +01:00
Multi-improvements
- Make lib instance shaders multiply color value instead of overriding it - Improve MultiBlockModelBuilder - Accept an Iterable<BlockPos> instead of a Collection<StructureBlockInfo> and assume all block state data is already contained within the render world - Accept a Function instead of a Map as the model data lookup - Allow enabling fluid rendering (all rendered fluids are currently unshaded) - Refactor VirtualEmptyBlockGetter - Move elementary implementations into abstract VirtualBlockGetter class - Extract virtual LevelLightEngine into separate VirtualLightEngine class with ability to lookup light values per pos - Turn VirtualEmptyBlockGetter into a class and make all methods final to ensure instances of this class are actually empty even if subclassed - Make BakedModelBufferer class package private - Remove unused VertexTransformations class - Remove Experimental annotation from VisualizationContext.createEmbedding
This commit is contained in:
parent
eb22fee6ae
commit
bf3b8ea89b
@ -1,7 +1,5 @@
|
||||
package com.jozufozu.flywheel.api.visualization;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import com.jozufozu.flywheel.api.BackendImplemented;
|
||||
import com.jozufozu.flywheel.api.instance.InstancerProvider;
|
||||
|
||||
@ -24,6 +22,5 @@ public interface VisualizationContext {
|
||||
*/
|
||||
Vec3i renderOrigin();
|
||||
|
||||
@ApiStatus.Experimental
|
||||
VisualEmbedding createEmbedding();
|
||||
}
|
||||
|
@ -11,16 +11,16 @@ import com.jozufozu.flywheel.api.model.Model;
|
||||
|
||||
public class SingleMeshModel implements Model {
|
||||
private final Mesh mesh;
|
||||
private final Material material;
|
||||
private final ImmutableList<ConfiguredMesh> meshList;
|
||||
|
||||
public SingleMeshModel(Mesh mesh, Material material) {
|
||||
this.mesh = mesh;
|
||||
this.material = material;
|
||||
meshList = ImmutableList.of(new ConfiguredMesh(material, mesh));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConfiguredMesh> meshes() {
|
||||
return ImmutableList.of(new ConfiguredMesh(material, mesh));
|
||||
return meshList;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.jozufozu.flywheel.lib.model.baked;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Iterator;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ -11,6 +11,7 @@ import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
|
||||
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;
|
||||
@ -21,11 +22,11 @@ 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.levelgen.structure.templatesystem.StructureTemplate;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraftforge.client.ChunkRenderTypeSet;
|
||||
import net.minecraftforge.client.model.data.ModelData;
|
||||
|
||||
public final class BakedModelBufferer {
|
||||
final class BakedModelBufferer {
|
||||
private static final RenderType[] CHUNK_LAYERS = RenderType.chunkBufferLayers().toArray(RenderType[]::new);
|
||||
private static final int CHUNK_LAYER_AMOUNT = CHUNK_LAYERS.length;
|
||||
|
||||
@ -122,12 +123,13 @@ public final class BakedModelBufferer {
|
||||
bufferSingleShadeSeparated(renderDispatcher.getModelRenderer(), renderWorld, renderDispatcher.getBlockModel(state), state, poseStack, modelData, resultConsumer);
|
||||
}
|
||||
|
||||
public static void bufferMultiBlock(Collection<StructureTemplate.StructureBlockInfo> blocks, BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, @Nullable PoseStack poseStack, Map<BlockPos, ModelData> modelDataMap, ResultConsumer resultConsumer) {
|
||||
public static void bufferMultiBlock(BlockRenderDispatcher renderDispatcher, Iterator<BlockPos> posIterator, BlockAndTintGetter renderWorld, @Nullable PoseStack poseStack, Function<BlockPos, ModelData> modelDataLookup, boolean renderFluids, ResultConsumer resultConsumer) {
|
||||
ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
|
||||
if (poseStack == null) {
|
||||
poseStack = objects.identityPoseStack;
|
||||
}
|
||||
RandomSource random = objects.random;
|
||||
TransformingVertexConsumer transformingWrapper = objects.transformingWrapper;
|
||||
|
||||
BufferBuilder[] buffers = objects.shadedBuffers;
|
||||
for (BufferBuilder buffer : buffers) {
|
||||
@ -137,35 +139,51 @@ public final class BakedModelBufferer {
|
||||
ModelBlockRenderer blockRenderer = renderDispatcher.getModelRenderer();
|
||||
ModelBlockRenderer.enableCaching();
|
||||
|
||||
for (StructureTemplate.StructureBlockInfo blockInfo : blocks) {
|
||||
BlockState state = blockInfo.state();
|
||||
while (posIterator.hasNext()) {
|
||||
BlockPos pos = posIterator.next();
|
||||
BlockState state = renderWorld.getBlockState(pos);
|
||||
|
||||
if (state.getRenderShape() != RenderShape.MODEL) {
|
||||
continue;
|
||||
if (renderFluids) {
|
||||
FluidState fluidState = state.getFluidState();
|
||||
|
||||
if (!fluidState.isEmpty()) {
|
||||
RenderType layer = ItemBlockRenderTypes.getRenderLayer(fluidState);
|
||||
int layerIndex = layer.getChunkLayerId();
|
||||
|
||||
transformingWrapper.prepare(buffers[layerIndex], poseStack);
|
||||
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(pos.getX() - (pos.getX() & 0xF), pos.getY() - (pos.getY() & 0xF), pos.getZ() - (pos.getZ() & 0xF));
|
||||
renderDispatcher.renderLiquid(pos, renderWorld, transformingWrapper, state, fluidState);
|
||||
poseStack.popPose();
|
||||
}
|
||||
}
|
||||
|
||||
BlockPos pos = blockInfo.pos();
|
||||
long seed = state.getSeed(pos);
|
||||
BakedModel model = renderDispatcher.getBlockModel(state);
|
||||
ModelData modelData = modelDataMap.getOrDefault(pos, ModelData.EMPTY);
|
||||
modelData = model.getModelData(renderWorld, pos, state, modelData);
|
||||
random.setSeed(seed);
|
||||
ChunkRenderTypeSet renderTypes = model.getRenderTypes(state, random, modelData);
|
||||
if (state.getRenderShape() == RenderShape.MODEL) {
|
||||
long seed = state.getSeed(pos);
|
||||
BakedModel model = renderDispatcher.getBlockModel(state);
|
||||
ModelData modelData = modelDataLookup.apply(pos);
|
||||
modelData = model.getModelData(renderWorld, pos, state, modelData);
|
||||
random.setSeed(seed);
|
||||
ChunkRenderTypeSet renderTypes = model.getRenderTypes(state, random, modelData);
|
||||
|
||||
for (RenderType renderType : renderTypes) {
|
||||
int layerIndex = renderType.getChunkLayerId();
|
||||
|
||||
BufferBuilder buffer = buffers[layerIndex];
|
||||
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(pos.getX(), pos.getY(), pos.getZ());
|
||||
blockRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, buffer, true, random, seed, OverlayTexture.NO_OVERLAY, modelData, renderType);
|
||||
poseStack.popPose();
|
||||
for (RenderType renderType : renderTypes) {
|
||||
int layerIndex = renderType.getChunkLayerId();
|
||||
|
||||
BufferBuilder buffer = buffers[layerIndex];
|
||||
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(pos.getX(), pos.getY(), pos.getZ());
|
||||
blockRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, buffer, true, random, seed, OverlayTexture.NO_OVERLAY, modelData, renderType);
|
||||
poseStack.popPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ModelBlockRenderer.clearCache();
|
||||
|
||||
transformingWrapper.clear();
|
||||
|
||||
for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) {
|
||||
RenderType renderType = CHUNK_LAYERS[layerIndex];
|
||||
BufferBuilder buffer = buffers[layerIndex];
|
||||
@ -177,13 +195,14 @@ public final class BakedModelBufferer {
|
||||
}
|
||||
}
|
||||
|
||||
public static void bufferMultiBlockShadeSeparated(Collection<StructureTemplate.StructureBlockInfo> blocks, BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, @Nullable PoseStack poseStack, Map<BlockPos, ModelData> modelDataMap, ShadeSeparatedResultConsumer resultConsumer) {
|
||||
public static void bufferMultiBlockShadeSeparated(BlockRenderDispatcher renderDispatcher, Iterator<BlockPos> posIterator, BlockAndTintGetter renderWorld, @Nullable PoseStack poseStack, Function<BlockPos, ModelData> modelDataLookup, boolean renderFluids, ShadeSeparatedResultConsumer resultConsumer) {
|
||||
ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
|
||||
if (poseStack == null) {
|
||||
poseStack = objects.identityPoseStack;
|
||||
}
|
||||
RandomSource random = objects.random;
|
||||
ShadeSeparatingVertexConsumer shadeSeparatingWrapper = objects.shadeSeparatingWrapper;
|
||||
TransformingVertexConsumer transformingWrapper = objects.transformingWrapper;
|
||||
|
||||
BufferBuilder[] shadedBuffers = objects.shadedBuffers;
|
||||
BufferBuilder[] unshadedBuffers = objects.unshadedBuffers;
|
||||
@ -197,36 +216,51 @@ public final class BakedModelBufferer {
|
||||
ModelBlockRenderer blockRenderer = renderDispatcher.getModelRenderer();
|
||||
ModelBlockRenderer.enableCaching();
|
||||
|
||||
for (StructureTemplate.StructureBlockInfo blockInfo : blocks) {
|
||||
BlockState state = blockInfo.state();
|
||||
while (posIterator.hasNext()) {
|
||||
BlockPos pos = posIterator.next();
|
||||
BlockState state = renderWorld.getBlockState(pos);
|
||||
|
||||
if (state.getRenderShape() != RenderShape.MODEL) {
|
||||
continue;
|
||||
if (renderFluids) {
|
||||
FluidState fluidState = state.getFluidState();
|
||||
|
||||
if (!fluidState.isEmpty()) {
|
||||
RenderType layer = ItemBlockRenderTypes.getRenderLayer(fluidState);
|
||||
int layerIndex = layer.getChunkLayerId();
|
||||
|
||||
transformingWrapper.prepare(shadedBuffers[layerIndex], poseStack);
|
||||
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(pos.getX() - (pos.getX() & 0xF), pos.getY() - (pos.getY() & 0xF), pos.getZ() - (pos.getZ() & 0xF));
|
||||
renderDispatcher.renderLiquid(pos, renderWorld, transformingWrapper, state, fluidState);
|
||||
poseStack.popPose();
|
||||
}
|
||||
}
|
||||
|
||||
BlockPos pos = blockInfo.pos();
|
||||
long seed = state.getSeed(pos);
|
||||
BakedModel model = renderDispatcher.getBlockModel(state);
|
||||
ModelData modelData = modelDataMap.getOrDefault(pos, ModelData.EMPTY);
|
||||
modelData = model.getModelData(renderWorld, pos, state, modelData);
|
||||
random.setSeed(seed);
|
||||
ChunkRenderTypeSet renderTypes = model.getRenderTypes(state, random, modelData);
|
||||
if (state.getRenderShape() == RenderShape.MODEL) {
|
||||
long seed = state.getSeed(pos);
|
||||
BakedModel model = renderDispatcher.getBlockModel(state);
|
||||
ModelData modelData = modelDataLookup.apply(pos);
|
||||
modelData = model.getModelData(renderWorld, pos, state, modelData);
|
||||
random.setSeed(seed);
|
||||
ChunkRenderTypeSet renderTypes = model.getRenderTypes(state, random, modelData);
|
||||
|
||||
for (RenderType renderType : renderTypes) {
|
||||
int layerIndex = renderType.getChunkLayerId();
|
||||
for (RenderType renderType : renderTypes) {
|
||||
int layerIndex = renderType.getChunkLayerId();
|
||||
|
||||
shadeSeparatingWrapper.prepare(shadedBuffers[layerIndex], unshadedBuffers[layerIndex]);
|
||||
shadeSeparatingWrapper.prepare(shadedBuffers[layerIndex], unshadedBuffers[layerIndex]);
|
||||
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(pos.getX(), pos.getY(), pos.getZ());
|
||||
blockRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, shadeSeparatingWrapper, true, random, seed, OverlayTexture.NO_OVERLAY, modelData, renderType);
|
||||
poseStack.popPose();
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(pos.getX(), pos.getY(), pos.getZ());
|
||||
blockRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, shadeSeparatingWrapper, true, random, seed, OverlayTexture.NO_OVERLAY, modelData, renderType);
|
||||
poseStack.popPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ModelBlockRenderer.clearCache();
|
||||
|
||||
shadeSeparatingWrapper.clear();
|
||||
transformingWrapper.clear();
|
||||
|
||||
for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) {
|
||||
RenderType renderType = CHUNK_LAYERS[layerIndex];
|
||||
@ -258,6 +292,7 @@ public final class BakedModelBufferer {
|
||||
public final RandomSource random = RandomSource.createNewThreadLocalInstance();
|
||||
|
||||
public final ShadeSeparatingVertexConsumer shadeSeparatingWrapper = new ShadeSeparatingVertexConsumer();
|
||||
public final TransformingVertexConsumer transformingWrapper = new TransformingVertexConsumer();
|
||||
|
||||
public final BufferBuilder[] shadedBuffers = new BufferBuilder[CHUNK_LAYER_AMOUNT];
|
||||
public final BufferBuilder[] unshadedBuffers = new BufferBuilder[CHUNK_LAYER_AMOUNT];
|
||||
|
@ -23,22 +23,17 @@ import net.minecraftforge.client.model.data.ModelData;
|
||||
|
||||
public class BakedModelBuilder {
|
||||
private final BakedModel bakedModel;
|
||||
private boolean shadeSeparated = true;
|
||||
private BlockAndTintGetter renderWorld;
|
||||
private BlockState blockState;
|
||||
private PoseStack poseStack;
|
||||
private ModelData modelData;
|
||||
private boolean shadeSeparated = true;
|
||||
private BiFunction<RenderType, Boolean, Material> materialFunc;
|
||||
|
||||
public BakedModelBuilder(BakedModel bakedModel) {
|
||||
this.bakedModel = bakedModel;
|
||||
}
|
||||
|
||||
public BakedModelBuilder disableShadeSeparation() {
|
||||
shadeSeparated = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BakedModelBuilder renderWorld(BlockAndTintGetter renderWorld) {
|
||||
this.renderWorld = renderWorld;
|
||||
return this;
|
||||
@ -59,6 +54,11 @@ public class BakedModelBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public BakedModelBuilder disableShadeSeparation() {
|
||||
shadeSeparated = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BakedModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
|
||||
this.materialFunc = materialFunc;
|
||||
return this;
|
||||
|
@ -21,21 +21,16 @@ import net.minecraftforge.client.model.data.ModelData;
|
||||
|
||||
public class BlockModelBuilder {
|
||||
private final BlockState state;
|
||||
private boolean shadeSeparated = true;
|
||||
private BlockAndTintGetter renderWorld;
|
||||
private PoseStack poseStack;
|
||||
private ModelData modelData;
|
||||
private boolean shadeSeparated = true;
|
||||
private BiFunction<RenderType, Boolean, Material> materialFunc;
|
||||
|
||||
public BlockModelBuilder(BlockState state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public BlockModelBuilder disableShadeSeparation() {
|
||||
shadeSeparated = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockModelBuilder renderWorld(BlockAndTintGetter renderWorld) {
|
||||
this.renderWorld = renderWorld;
|
||||
return this;
|
||||
@ -51,6 +46,11 @@ public class BlockModelBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockModelBuilder disableShadeSeparation() {
|
||||
shadeSeparated = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
|
||||
this.materialFunc = materialFunc;
|
||||
return this;
|
||||
|
@ -1,9 +1,7 @@
|
||||
package com.jozufozu.flywheel.lib.model.baked;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
@ -20,29 +18,20 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
|
||||
import net.minecraftforge.client.model.data.ModelData;
|
||||
|
||||
public class MultiBlockModelBuilder {
|
||||
private final Collection<StructureTemplate.StructureBlockInfo> blocks;
|
||||
private boolean shadeSeparated = true;
|
||||
private BlockAndTintGetter renderWorld;
|
||||
private final BlockAndTintGetter renderWorld;
|
||||
private final Iterable<BlockPos> positions;
|
||||
private PoseStack poseStack;
|
||||
private Map<BlockPos, ModelData> modelDataMap;
|
||||
private Function<BlockPos, ModelData> modelDataLookup;
|
||||
private boolean renderFluids = false;
|
||||
private boolean shadeSeparated = true;
|
||||
private BiFunction<RenderType, Boolean, Material> materialFunc;
|
||||
|
||||
public MultiBlockModelBuilder(Collection<StructureTemplate.StructureBlockInfo> blocks) {
|
||||
this.blocks = blocks;
|
||||
}
|
||||
|
||||
public MultiBlockModelBuilder disableShadeSeparation() {
|
||||
shadeSeparated = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MultiBlockModelBuilder renderWorld(BlockAndTintGetter renderWorld) {
|
||||
public MultiBlockModelBuilder(BlockAndTintGetter renderWorld, Iterable<BlockPos> positions) {
|
||||
this.renderWorld = renderWorld;
|
||||
return this;
|
||||
this.positions = positions;
|
||||
}
|
||||
|
||||
public MultiBlockModelBuilder poseStack(PoseStack poseStack) {
|
||||
@ -50,8 +39,18 @@ public class MultiBlockModelBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public MultiBlockModelBuilder modelDataMap(Map<BlockPos, ModelData> modelDataMap) {
|
||||
this.modelDataMap = modelDataMap;
|
||||
public MultiBlockModelBuilder modelDataLookup(Function<BlockPos, ModelData> modelDataLookup) {
|
||||
this.modelDataLookup = modelDataLookup;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MultiBlockModelBuilder enableFluidRendering() {
|
||||
renderFluids = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MultiBlockModelBuilder disableShadeSeparation() {
|
||||
shadeSeparated = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -61,11 +60,8 @@ public class MultiBlockModelBuilder {
|
||||
}
|
||||
|
||||
public TessellatedModel build() {
|
||||
if (renderWorld == null) {
|
||||
renderWorld = VirtualEmptyBlockGetter.INSTANCE;
|
||||
}
|
||||
if (modelDataMap == null) {
|
||||
modelDataMap = Collections.emptyMap();
|
||||
if (modelDataLookup == null) {
|
||||
modelDataLookup = pos -> ModelData.EMPTY;
|
||||
}
|
||||
if (materialFunc == null) {
|
||||
materialFunc = ModelUtil::getMaterial;
|
||||
@ -83,7 +79,7 @@ public class MultiBlockModelBuilder {
|
||||
out.add(new Model.ConfiguredMesh(material, mesh));
|
||||
}
|
||||
};
|
||||
BakedModelBufferer.bufferMultiBlockShadeSeparated(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, modelDataMap, resultConsumer);
|
||||
BakedModelBufferer.bufferMultiBlockShadeSeparated(ModelUtil.VANILLA_RENDERER, positions.iterator(), renderWorld, poseStack, modelDataLookup, renderFluids, resultConsumer);
|
||||
} else {
|
||||
ResultConsumer resultConsumer = (renderType, data) -> {
|
||||
Material material = materialFunc.apply(renderType, true);
|
||||
@ -94,7 +90,7 @@ public class MultiBlockModelBuilder {
|
||||
out.add(new Model.ConfiguredMesh(material, mesh));
|
||||
}
|
||||
};
|
||||
BakedModelBufferer.bufferMultiBlock(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, modelDataMap, resultConsumer);
|
||||
BakedModelBufferer.bufferMultiBlock(ModelUtil.VANILLA_RENDERER, positions.iterator(), renderWorld, poseStack, modelDataLookup, renderFluids, resultConsumer);
|
||||
}
|
||||
|
||||
return new TessellatedModel(out.build(), shadeSeparated);
|
||||
|
@ -0,0 +1,88 @@
|
||||
package com.jozufozu.flywheel.lib.model.baked;
|
||||
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
import com.jozufozu.flywheel.lib.math.MatrixMath;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
class TransformingVertexConsumer implements VertexConsumer {
|
||||
private VertexConsumer delegate;
|
||||
private PoseStack poseStack;
|
||||
|
||||
public void prepare(VertexConsumer delegate, PoseStack poseStack) {
|
||||
this.delegate = delegate;
|
||||
this.poseStack = poseStack;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
delegate = null;
|
||||
poseStack = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer vertex(double x, double y, double z) {
|
||||
Matrix4f matrix = poseStack.last().pose();
|
||||
float fx = (float) x;
|
||||
float fy = (float) y;
|
||||
float fz = (float) z;
|
||||
delegate.vertex(
|
||||
MatrixMath.transformPositionX(matrix, fx, fy, fz),
|
||||
MatrixMath.transformPositionY(matrix, fx, fy, fz),
|
||||
MatrixMath.transformPositionZ(matrix, fx, fy, fz));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer color(int red, int green, int blue, int alpha) {
|
||||
delegate.color(red, green, blue, alpha);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer uv(float u, float v) {
|
||||
delegate.uv(u, v);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer overlayCoords(int u, int v) {
|
||||
delegate.overlayCoords(u, v);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer uv2(int u, int v) {
|
||||
delegate.uv2(u, v);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer normal(float x, float y, float z) {
|
||||
Matrix3f matrix = poseStack.last().normal();
|
||||
float fx = (float) x;
|
||||
float fy = (float) y;
|
||||
float fz = (float) z;
|
||||
delegate.normal(
|
||||
MatrixMath.transformNormalX(matrix, fx, fy, fz),
|
||||
MatrixMath.transformNormalY(matrix, fx, fy, fz),
|
||||
MatrixMath.transformNormalZ(matrix, fx, fy, fz));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVertex() {
|
||||
delegate.endVertex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defaultColor(int red, int green, int blue, int alpha) {
|
||||
delegate.defaultColor(red, green, blue, alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetDefaultColor() {
|
||||
delegate.unsetDefaultColor();
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package com.jozufozu.flywheel.lib.model.baked;
|
||||
|
||||
import java.util.function.ToIntFunction;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.ColorResolver;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.Biomes;
|
||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
|
||||
public abstract class VirtualBlockGetter implements BlockAndTintGetter {
|
||||
protected final VirtualLightEngine lightEngine;
|
||||
|
||||
public VirtualBlockGetter(ToIntFunction<BlockPos> blockLightFunc, ToIntFunction<BlockPos> skyLightFunc) {
|
||||
lightEngine = new VirtualLightEngine(blockLightFunc, skyLightFunc, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidState getFluidState(BlockPos pos) {
|
||||
return getBlockState(pos).getFluidState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getShade(Direction direction, boolean shaded) {
|
||||
return 1f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelLightEngine getLightEngine() {
|
||||
return lightEngine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockTint(BlockPos pos, ColorResolver resolver) {
|
||||
Biome plainsBiome = Minecraft.getInstance().getConnection().registryAccess().registryOrThrow(Registries.BIOME).getOrThrow(Biomes.PLAINS);
|
||||
return resolver.getColor(plainsBiome, pos.getX(), pos.getZ());
|
||||
}
|
||||
}
|
@ -1,34 +1,25 @@
|
||||
package com.jozufozu.flywheel.lib.model.baked;
|
||||
|
||||
import java.util.function.ToIntFunction;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.ColorResolver;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.Biomes;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.DataLayer;
|
||||
import net.minecraft.world.level.chunk.LightChunk;
|
||||
import net.minecraft.world.level.chunk.LightChunkGetter;
|
||||
import net.minecraft.world.level.lighting.LayerLightEventListener;
|
||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
|
||||
public interface VirtualEmptyBlockGetter extends BlockAndTintGetter {
|
||||
public static final VirtualEmptyBlockGetter INSTANCE = new StaticLightImpl(0, 15);
|
||||
public static final VirtualEmptyBlockGetter FULL_BRIGHT = new StaticLightImpl(15, 15);
|
||||
public static final VirtualEmptyBlockGetter FULL_DARK = new StaticLightImpl(0, 0);
|
||||
public class VirtualEmptyBlockGetter extends VirtualBlockGetter {
|
||||
public static final VirtualEmptyBlockGetter INSTANCE = new VirtualEmptyBlockGetter(p -> 0, p -> 15);
|
||||
public static final VirtualEmptyBlockGetter FULL_BRIGHT = new VirtualEmptyBlockGetter(p -> 15, p -> 15);
|
||||
public static final VirtualEmptyBlockGetter FULL_DARK = new VirtualEmptyBlockGetter(p -> 0, p -> 0);
|
||||
|
||||
public VirtualEmptyBlockGetter(ToIntFunction<BlockPos> blockLightFunc, ToIntFunction<BlockPos> skyLightFunc) {
|
||||
super(blockLightFunc, skyLightFunc);
|
||||
}
|
||||
|
||||
public static boolean is(BlockAndTintGetter blockGetter) {
|
||||
return blockGetter instanceof VirtualEmptyBlockGetter;
|
||||
@ -36,110 +27,27 @@ public interface VirtualEmptyBlockGetter extends BlockAndTintGetter {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default BlockEntity getBlockEntity(BlockPos pos) {
|
||||
public final BlockEntity getBlockEntity(BlockPos pos) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockState getBlockState(BlockPos pos) {
|
||||
public final BlockState getBlockState(BlockPos pos) {
|
||||
return Blocks.AIR.defaultBlockState();
|
||||
}
|
||||
|
||||
@Override
|
||||
default FluidState getFluidState(BlockPos pos) {
|
||||
public final FluidState getFluidState(BlockPos pos) {
|
||||
return Fluids.EMPTY.defaultFluidState();
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getHeight() {
|
||||
public final int getHeight() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getMinBuildHeight() {
|
||||
public final int getMinBuildHeight() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
default float getShade(Direction direction, boolean shaded) {
|
||||
return 1f;
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getBlockTint(BlockPos pos, ColorResolver resolver) {
|
||||
Biome plainsBiome = Minecraft.getInstance().getConnection().registryAccess().registryOrThrow(Registries.BIOME).getOrThrow(Biomes.PLAINS);
|
||||
return resolver.getColor(plainsBiome, pos.getX(), pos.getZ());
|
||||
}
|
||||
|
||||
public static class StaticLightImpl implements VirtualEmptyBlockGetter {
|
||||
private final LevelLightEngine lightEngine;
|
||||
|
||||
public StaticLightImpl(int blockLight, int skyLight) {
|
||||
lightEngine = new LevelLightEngine(new LightChunkGetter() {
|
||||
@Override
|
||||
@Nullable
|
||||
public LightChunk getChunkForLighting(int x, int z) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockGetter getLevel() {
|
||||
return StaticLightImpl.this;
|
||||
}
|
||||
}, false, false) {
|
||||
private final LayerLightEventListener blockListener = createStaticListener(blockLight);
|
||||
private final LayerLightEventListener skyListener = createStaticListener(skyLight);
|
||||
|
||||
@Override
|
||||
public LayerLightEventListener getLayerListener(LightLayer layer) {
|
||||
return layer == LightLayer.BLOCK ? blockListener : skyListener;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static LayerLightEventListener createStaticListener(int light) {
|
||||
return new LayerLightEventListener() {
|
||||
@Override
|
||||
public void checkBlock(BlockPos pos) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLightWork() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int runLightUpdates() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSectionStatus(SectionPos pos, boolean isSectionEmpty) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightEnabled(ChunkPos pos, boolean lightEnabled) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propagateLightSources(ChunkPos pos) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLayer getDataLayerData(SectionPos pos) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue(BlockPos pos) {
|
||||
return light;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelLightEngine getLightEngine() {
|
||||
return lightEngine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,95 @@
|
||||
package com.jozufozu.flywheel.lib.model.baked;
|
||||
|
||||
import java.util.function.ToIntFunction;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
import net.minecraft.world.level.chunk.DataLayer;
|
||||
import net.minecraft.world.level.chunk.LightChunk;
|
||||
import net.minecraft.world.level.chunk.LightChunkGetter;
|
||||
import net.minecraft.world.level.lighting.LayerLightEventListener;
|
||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
|
||||
public final class VirtualLightEngine extends LevelLightEngine {
|
||||
private final LayerLightEventListener blockListener;
|
||||
private final LayerLightEventListener skyListener;
|
||||
|
||||
public VirtualLightEngine(ToIntFunction<BlockPos> blockLightFunc, ToIntFunction<BlockPos> skyLightFunc, BlockGetter level) {
|
||||
super(new LightChunkGetter() {
|
||||
@Override
|
||||
@Nullable
|
||||
public LightChunk getChunkForLighting(int x, int z) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockGetter getLevel() {
|
||||
return level;
|
||||
}
|
||||
}, false, false);
|
||||
|
||||
blockListener = new VirtualLayerLightEventListener(blockLightFunc);
|
||||
skyListener = new VirtualLayerLightEventListener(skyLightFunc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayerLightEventListener getLayerListener(LightLayer layer) {
|
||||
return layer == LightLayer.BLOCK ? blockListener : skyListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRawBrightness(BlockPos pos, int amount) {
|
||||
int i = skyListener.getLightValue(pos) - amount;
|
||||
int j = blockListener.getLightValue(pos);
|
||||
return Math.max(j, i);
|
||||
}
|
||||
|
||||
private static class VirtualLayerLightEventListener implements LayerLightEventListener {
|
||||
private final ToIntFunction<BlockPos> lightFunc;
|
||||
|
||||
public VirtualLayerLightEventListener(ToIntFunction<BlockPos> lightFunc) {
|
||||
this.lightFunc = lightFunc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkBlock(BlockPos pos) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLightWork() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int runLightUpdates() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSectionStatus(SectionPos pos, boolean isSectionEmpty) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightEnabled(ChunkPos pos, boolean lightEnabled) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propagateLightSources(ChunkPos pos) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLayer getDataLayerData(SectionPos pos) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue(BlockPos pos) {
|
||||
return lightFunc.applyAsInt(pos);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package com.jozufozu.flywheel.lib.vertex;
|
||||
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.MutableVertexList;
|
||||
import com.jozufozu.flywheel.lib.math.MatrixMath;
|
||||
|
||||
public final class VertexTransformations {
|
||||
private VertexTransformations() {
|
||||
}
|
||||
|
||||
public static void transformPos(MutableVertexList vertexList, int index, Matrix4f matrix) {
|
||||
float x = vertexList.x(index);
|
||||
float y = vertexList.y(index);
|
||||
float z = vertexList.z(index);
|
||||
vertexList.x(index, MatrixMath.transformPositionX(matrix, x, y, z));
|
||||
vertexList.y(index, MatrixMath.transformPositionY(matrix, x, y, z));
|
||||
vertexList.z(index, MatrixMath.transformPositionZ(matrix, x, y, z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assumes the matrix preserves scale.
|
||||
*/
|
||||
public static void transformNormal(MutableVertexList vertexList, int index, Matrix3f matrix) {
|
||||
float nx = vertexList.normalX(index);
|
||||
float ny = vertexList.normalY(index);
|
||||
float nz = vertexList.normalZ(index);
|
||||
float tnx = MatrixMath.transformNormalX(matrix, nx, ny, nz);
|
||||
float tny = MatrixMath.transformNormalY(matrix, nx, ny, nz);
|
||||
float tnz = MatrixMath.transformNormalZ(matrix, nx, ny, nz);
|
||||
// seems to be the case that sqrLength is always ~1.0
|
||||
// float sqrLength = fma(tnx, tnx, fma(tny, tny, tnz * tnz));
|
||||
// if (sqrLength != 0) {
|
||||
// float f = invsqrt(sqrLength);
|
||||
// tnx *= f;
|
||||
// tny *= f;
|
||||
// tnz *= f;
|
||||
// }
|
||||
vertexList.normalX(index, tnx);
|
||||
vertexList.normalY(index, tny);
|
||||
vertexList.normalZ(index, tnz);
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
void flw_instanceVertex(in FlwInstance i) {
|
||||
flw_vertexPos = vec4(rotateByQuaternion(flw_vertexPos.xyz - i.pivot, i.rotation) + i.pivot + i.position, 1.0);
|
||||
flw_vertexNormal = rotateByQuaternion(flw_vertexNormal, i.rotation);
|
||||
flw_vertexColor = i.color;
|
||||
flw_vertexColor *= i.color;
|
||||
flw_vertexOverlay = i.overlay;
|
||||
flw_vertexLight = i.light / 15.;
|
||||
}
|
||||
|
@ -7,6 +7,4 @@ void flw_instanceVertex(in FlwInstance i) {
|
||||
flw_vertexTexCoord = (flw_vertexPos.xz - i.entityPosXZ) * 0.5 / i.radius + 0.5;
|
||||
|
||||
flw_vertexColor.a = i.alpha;
|
||||
// no overlay
|
||||
flw_vertexOverlay = ivec2(0, 10);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
void flw_instanceVertex(in FlwInstance i) {
|
||||
flw_vertexPos = i.pose * flw_vertexPos;
|
||||
flw_vertexNormal = i.normal * flw_vertexNormal;
|
||||
flw_vertexColor = i.color;
|
||||
flw_vertexColor *= i.color;
|
||||
flw_vertexOverlay = i.overlay;
|
||||
flw_vertexLight = i.light / 15.;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user