Skip to content

Commit

Permalink
Fix mesh order of models from model builders
Browse files Browse the repository at this point in the history
Meshes are now always sorted by chunk layer first, then in order of how the BakedModel returned quads. This should exactly match vanilla's chunk buffering and avoid any rendering issues.
  • Loading branch information
PepperCode1 authored and Jozufozu committed May 17, 2024
1 parent 914ce0a commit 7ef9ce3
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@

import org.joml.Vector4fc;

import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.api.model.Model;

public class SimpleModel implements Model {
private final ImmutableList<ConfiguredMesh> meshes;
private final List<ConfiguredMesh> meshes;
private final Vector4fc boundingSphere;

public SimpleModel(ImmutableList<ConfiguredMesh> meshes) {
public SimpleModel(List<ConfiguredMesh> meshes) {
this.meshes = meshes;
this.boundingSphere = ModelUtil.computeBoundingSphere(meshes);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
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;
static final RenderType[] CHUNK_LAYERS = RenderType.chunkBufferLayers().toArray(RenderType[]::new);
static final int CHUNK_LAYER_AMOUNT = CHUNK_LAYERS.length;

private static final ThreadLocal<ThreadLocalObjects> THREAD_LOCAL_OBJECTS = ThreadLocal.withInitial(ThreadLocalObjects::new);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.jozufozu.flywheel.lib.model.baked;

import java.util.List;

import com.google.common.collect.ImmutableList;

import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap;
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
import net.minecraft.client.renderer.RenderType;

class ChunkLayerSortedListBuilder<T> {
private static final ThreadLocal<ChunkLayerSortedListBuilder<?>> THREAD_LOCAL = ThreadLocal.withInitial(ChunkLayerSortedListBuilder::new);

@SuppressWarnings("unchecked")
private final ObjectArrayList<T>[] lists = new ObjectArrayList[BakedModelBufferer.CHUNK_LAYER_AMOUNT];
private final Reference2ReferenceMap<RenderType, ObjectArrayList<T>> map = new Reference2ReferenceOpenHashMap<>();

private ChunkLayerSortedListBuilder() {
for (int layerIndex = 0; layerIndex < BakedModelBufferer.CHUNK_LAYER_AMOUNT; layerIndex++) {
RenderType renderType = BakedModelBufferer.CHUNK_LAYERS[layerIndex];
ObjectArrayList<T> list = new ObjectArrayList<>();
lists[layerIndex] = list;
map.put(renderType, list);
}
}

@SuppressWarnings("unchecked")
public static <T> ChunkLayerSortedListBuilder<T> getThreadLocal() {
return (ChunkLayerSortedListBuilder<T>) THREAD_LOCAL.get();
}

public void add(RenderType renderType, T obj) {
List<T> list = map.get(renderType);
if (list == null) {
throw new IllegalArgumentException("RenderType '" + renderType + "' is not a chunk layer");
}
list.add(obj);
}

@SuppressWarnings("unchecked")
public ImmutableList<T> build() {
int size = 0;
for (ObjectArrayList<T> list : lists) {
size += list.size();
}

T[] array = (T[]) new Object[size];
int destPos = 0;
for (ObjectArrayList<T> list : lists) {
System.arraycopy(list.elements(), 0, array, destPos, list.size());
destPos += list.size();
list.clear();
}

return ImmutableList.copyOf(array);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

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;
Expand Down Expand Up @@ -60,18 +59,18 @@ public SimpleModel build() {
materialFunc = ModelUtil::getMaterial;
}

var out = ImmutableList.<Model.ConfiguredMesh>builder();
var builder = ChunkLayerSortedListBuilder.<Model.ConfiguredMesh>getThreadLocal();

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));
builder.add(renderType, new Model.ConfiguredMesh(material, mesh));
}
});

return new SimpleModel(out.build());
return new SimpleModel(builder.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

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;
Expand Down Expand Up @@ -49,18 +48,18 @@ public SimpleModel build() {
materialFunc = ModelUtil::getMaterial;
}

var out = ImmutableList.<Model.ConfiguredMesh>builder();
var builder = ChunkLayerSortedListBuilder.<Model.ConfiguredMesh>getThreadLocal();

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));
builder.add(renderType, new Model.ConfiguredMesh(material, mesh));
}
});

return new SimpleModel(out.build());
return new SimpleModel(builder.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

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;
Expand Down Expand Up @@ -46,18 +45,18 @@ public SimpleModel build() {
materialFunc = ModelUtil::getMaterial;
}

var out = ImmutableList.<Model.ConfiguredMesh>builder();
var builder = ChunkLayerSortedListBuilder.<Model.ConfiguredMesh>getThreadLocal();

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));
builder.add(renderType, new Model.ConfiguredMesh(material, mesh));
}
});

return new SimpleModel(out.build());
return new SimpleModel(builder.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
import net.minecraftforge.client.model.data.ModelData;

final class BakedModelBufferer {
private static final RenderType[] CHUNK_LAYERS = RenderType.chunkBufferLayers().toArray(RenderType[]::new);
private static final int CHUNK_LAYER_AMOUNT = CHUNK_LAYERS.length;
static final RenderType[] CHUNK_LAYERS = RenderType.chunkBufferLayers().toArray(RenderType[]::new);
static final int CHUNK_LAYER_AMOUNT = CHUNK_LAYERS.length;

private static final ThreadLocal<ThreadLocalObjects> THREAD_LOCAL_OBJECTS = ThreadLocal.withInitial(ThreadLocalObjects::new);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.jozufozu.flywheel.lib.model.baked;

import java.util.List;

import com.google.common.collect.ImmutableList;

import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.client.renderer.RenderType;

class ChunkLayerSortedListBuilder<T> {
private static final ThreadLocal<ChunkLayerSortedListBuilder<?>> THREAD_LOCAL = ThreadLocal.withInitial(ChunkLayerSortedListBuilder::new);

@SuppressWarnings("unchecked")
private final ObjectArrayList<T>[] lists = new ObjectArrayList[BakedModelBufferer.CHUNK_LAYER_AMOUNT];

private ChunkLayerSortedListBuilder() {
for (int layerIndex = 0; layerIndex < BakedModelBufferer.CHUNK_LAYER_AMOUNT; layerIndex++) {
ObjectArrayList<T> list = new ObjectArrayList<>();
lists[layerIndex] = list;
}
}

@SuppressWarnings("unchecked")
public static <T> ChunkLayerSortedListBuilder<T> getThreadLocal() {
return (ChunkLayerSortedListBuilder<T>) THREAD_LOCAL.get();
}

public void add(RenderType renderType, T obj) {
int layerIndex = renderType.getChunkLayerId();
if (layerIndex == -1) {
throw new IllegalArgumentException("RenderType '" + renderType + "' is not a chunk layer");
}
List<T> list = lists[layerIndex];
list.add(obj);
}

@SuppressWarnings("unchecked")
public ImmutableList<T> build() {
int size = 0;
for (ObjectArrayList<T> list : lists) {
size += list.size();
}

T[] array = (T[]) new Object[size];
int destPos = 0;
for (ObjectArrayList<T> list : lists) {
System.arraycopy(list.elements(), 0, array, destPos, list.size());
destPos += list.size();
list.clear();
}

return ImmutableList.copyOf(array);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import org.jetbrains.annotations.Nullable;

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;
Expand Down Expand Up @@ -74,18 +73,18 @@ public SimpleModel build() {
modelData = ModelData.EMPTY;
}

var out = ImmutableList.<Model.ConfiguredMesh>builder();
var builder = ChunkLayerSortedListBuilder.<Model.ConfiguredMesh>getThreadLocal();

BakedModelBufferer.bufferSingle(ModelUtil.VANILLA_RENDERER.getModelRenderer(), level, bakedModel, blockState, poseStack, modelData, (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));
builder.add(renderType, new Model.ConfiguredMesh(material, mesh));
}
});

return new SimpleModel(out.build());
return new SimpleModel(builder.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import org.jetbrains.annotations.Nullable;

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;
Expand Down Expand Up @@ -63,18 +62,18 @@ public SimpleModel build() {
modelData = ModelData.EMPTY;
}

var out = ImmutableList.<Model.ConfiguredMesh>builder();
var builder = ChunkLayerSortedListBuilder.<Model.ConfiguredMesh>getThreadLocal();

BakedModelBufferer.bufferBlock(ModelUtil.VANILLA_RENDERER, level, state, poseStack, modelData, (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));
builder.add(renderType, new Model.ConfiguredMesh(material, mesh));
}
});

return new SimpleModel(out.build());
return new SimpleModel(builder.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import org.jetbrains.annotations.Nullable;

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;
Expand Down Expand Up @@ -61,18 +60,18 @@ public SimpleModel build() {
modelDataLookup = pos -> ModelData.EMPTY;
}

var out = ImmutableList.<Model.ConfiguredMesh>builder();
var builder = ChunkLayerSortedListBuilder.<Model.ConfiguredMesh>getThreadLocal();

BakedModelBufferer.bufferMultiBlock(ModelUtil.VANILLA_RENDERER, positions.iterator(), level, poseStack, modelDataLookup, 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));
builder.add(renderType, new Model.ConfiguredMesh(material, mesh));
}
});

return new SimpleModel(out.build());
return new SimpleModel(builder.build());
}
}

0 comments on commit 7ef9ce3

Please sign in to comment.