Many to many

- Models now return a list of ConfiguredMeshes, i.e. mesh-material pairs
- BufferedMeshes now poll the index pool as needed
- Inline BufferedMesh#write
This commit is contained in:
Jozufozu 2024-02-24 17:25:01 -06:00
parent d6abe89828
commit dd998058a3
11 changed files with 65 additions and 77 deletions

View file

@ -1,13 +1,13 @@
package com.jozufozu.flywheel.api.model;
import java.util.Map;
import java.util.List;
import org.joml.Vector4fc;
import com.jozufozu.flywheel.api.material.Material;
public interface Model {
Map<Material, Mesh> meshes();
List<ConfiguredMesh> meshes();
/**
* Get a vec4 representing this model's bounding sphere in the format (x, y, z, radius).
@ -17,9 +17,8 @@ public interface Model {
*/
Vector4fc boundingSphere();
// TODO: unused. remove?
@Deprecated
int vertexCount();
void delete();
record ConfiguredMesh(Material material, Mesh mesh) {
}
}

View file

@ -118,13 +118,13 @@ public class MeshPool {
mesh.byteIndex = byteIndex;
mesh.baseVertex = baseVertex;
mesh.write(vertexPtr, vertexView);
vertexView.ptr(vertexPtr + mesh.byteIndex);
vertexView.vertexCount(mesh.vertexCount);
mesh.mesh.write(vertexView);
byteIndex += mesh.byteSize();
baseVertex += mesh.vertexCount();
mesh.firstIndex = indexPool.firstIndex(mesh.mesh.indexSequence());
mesh.boundTo.clear();
}
@ -153,7 +153,6 @@ public class MeshPool {
private long byteIndex;
private int baseVertex;
private int firstIndex;
private int referenceCount = 0;
private final Set<GlVertexArray> boundTo = new ReferenceArraySet<>();
@ -181,7 +180,7 @@ public class MeshPool {
}
public int firstIndex() {
return firstIndex;
return indexPool.firstIndex(mesh.indexSequence());
}
public boolean deleted() {
@ -192,17 +191,11 @@ public class MeshPool {
return mesh.vertexCount() == 0 || deleted() || byteIndex == -1;
}
private void write(long ptr, VertexView vertexView) {
vertexView.ptr(ptr + byteIndex);
vertexView.vertexCount(vertexCount);
mesh.write(vertexView);
}
public void draw(int instanceCount) {
if (instanceCount > 1) {
GL32.glDrawElementsInstanced(GlPrimitive.TRIANGLES.glEnum, mesh.indexCount(), GL32.GL_UNSIGNED_INT, firstIndex, instanceCount);
GL32.glDrawElementsInstanced(GlPrimitive.TRIANGLES.glEnum, mesh.indexCount(), GL32.GL_UNSIGNED_INT, firstIndex(), instanceCount);
} else {
GL32.glDrawElements(GlPrimitive.TRIANGLES.glEnum, mesh.indexCount(), GL32.GL_UNSIGNED_INT, firstIndex);
GL32.glDrawElements(GlPrimitive.TRIANGLES.glEnum, mesh.indexCount(), GL32.GL_UNSIGNED_INT, firstIndex());
}
}

View file

@ -21,7 +21,6 @@ import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Mesh;
import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
@ -182,9 +181,9 @@ public class IndirectCullingGroup<I extends Instance> {
instancer.index = instancers.size();
instancers.add(instancer);
for (Map.Entry<Material, Mesh> entry : model.meshes().entrySet()) {
MeshPool.BufferedMesh bufferedMesh = meshPool.alloc(entry.getValue());
var draw = new IndirectDraw(instancer, entry.getKey(), bufferedMesh, stage);
for (var entry : model.meshes()) {
MeshPool.BufferedMesh bufferedMesh = meshPool.alloc(entry.mesh());
var draw = new IndirectDraw(instancer, entry.material(), bufferedMesh, stage);
indirectDraws.add(draw);
instancer.addDraw(draw);
}

View file

@ -78,10 +78,10 @@ public class InstancedDrawManager extends InstancerStorage<InstancedInstancer<?>
var meshes = key.model()
.meshes();
for (var entry : meshes.entrySet()) {
var mesh = meshPool.alloc(entry.getValue());
for (var entry : meshes) {
var mesh = meshPool.alloc(entry.mesh());
ShaderState shaderState = new ShaderState(entry.getKey(), key.type(), key.context());
ShaderState shaderState = new ShaderState(entry.material(), key.type(), key.context());
DrawCall drawCall = new DrawCall(instancer, mesh, shaderState);
drawSet.put(shaderState, drawCall);

View file

@ -2,6 +2,7 @@ package com.jozufozu.flywheel.lib.model;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.Collection;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
@ -11,6 +12,7 @@ import org.slf4j.Logger;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Mesh;
import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.vertex.VertexList;
import com.jozufozu.flywheel.api.vertex.VertexView;
import com.jozufozu.flywheel.api.vertex.VertexViewProviderRegistry;
@ -106,6 +108,10 @@ public final class ModelUtil {
return vertexCount;
}
public static Vector4f computeBoundingSphere(Collection<Model.ConfiguredMesh> meshes) {
return computeBoundingSphere(meshes.stream().map(Model.ConfiguredMesh::mesh).toList());
}
public static Vector4f computeBoundingSphere(Iterable<Mesh> meshes) {
int vertexCount = computeTotalVertexCount(meshes);
var block = MemoryBlock.malloc((long) vertexCount * PosVertexView.STRIDE);

View file

@ -1,27 +1,23 @@
package com.jozufozu.flywheel.lib.model;
import java.util.Map;
import java.util.List;
import org.joml.Vector4fc;
import com.google.common.collect.ImmutableMap;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Mesh;
import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.api.model.Model;
public class SimpleModel implements Model {
private final ImmutableMap<Material, Mesh> meshes;
private final ImmutableList<ConfiguredMesh> meshes;
private final Vector4fc boundingSphere;
private final int vertexCount;
public SimpleModel(ImmutableMap<Material, Mesh> meshes) {
public SimpleModel(ImmutableList<ConfiguredMesh> meshes) {
this.meshes = meshes;
this.boundingSphere = ModelUtil.computeBoundingSphere(meshes.values());
this.vertexCount = ModelUtil.computeTotalVertexCount(meshes.values());
this.boundingSphere = ModelUtil.computeBoundingSphere(meshes);
}
@Override
public Map<Material, Mesh> meshes() {
public List<ConfiguredMesh> meshes() {
return meshes;
}
@ -30,14 +26,10 @@ public class SimpleModel implements Model {
return boundingSphere;
}
@Override
public int vertexCount() {
return vertexCount;
}
@Override
public void delete() {
meshes.values()
.forEach(Mesh::delete);
}
for (ConfiguredMesh mesh : meshes) {
mesh.mesh().delete();
}
}
}

View file

@ -1,26 +1,26 @@
package com.jozufozu.flywheel.lib.model;
import java.util.Map;
import java.util.List;
import org.joml.Vector4fc;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Mesh;
import com.jozufozu.flywheel.api.model.Model;
public class SingleMeshModel implements Model {
private final Mesh mesh;
private final Map<Material, Mesh> meshMap;
private final Material material;
public SingleMeshModel(Mesh mesh, Material material) {
this.mesh = mesh;
meshMap = ImmutableMap.of(material, mesh);
this.material = material;
}
@Override
public Map<Material, Mesh> meshes() {
return meshMap;
public List<ConfiguredMesh> meshes() {
return ImmutableList.of(new ConfiguredMesh(material, mesh));
}
@Override
@ -28,11 +28,6 @@ public class SingleMeshModel implements Model {
return mesh.boundingSphere();
}
@Override
public int vertexCount() {
return mesh.vertexCount();
}
@Override
public void delete() {
mesh.delete();

View file

@ -2,9 +2,9 @@ package com.jozufozu.flywheel.lib.model.baked;
import java.util.function.BiFunction;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Mesh;
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;
@ -78,7 +78,7 @@ public class BakedModelBuilder {
materialFunc = ModelUtil::getMaterial;
}
ImmutableMap.Builder<Material, Mesh> meshMapBuilder = ImmutableMap.builder();
var out = ImmutableList.<Model.ConfiguredMesh>builder();
if (shadeSeparated) {
ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, data) -> {
@ -86,7 +86,8 @@ public class BakedModelBuilder {
if (material != null) {
VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
meshMapBuilder.put(material, 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));
}
};
BakedModelBufferer.bufferSingleShadeSeparated(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, modelData, resultConsumer);
@ -96,12 +97,13 @@ public class BakedModelBuilder {
if (material != null) {
VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
meshMapBuilder.put(material, new SimpleMesh(vertexView, meshData, "source=BakedModelBuilder," + "bakedModel=" + bakedModel + ",renderType=" + renderType));
var mesh = new SimpleMesh(vertexView, meshData, "source=BakedModelBuilder," + "bakedModel=" + bakedModel + ",renderType=" + renderType);
out.add(new Model.ConfiguredMesh(material, mesh));
}
};
BakedModelBufferer.bufferSingle(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, modelData, resultConsumer);
}
return new TessellatedModel(meshMapBuilder.build(), shadeSeparated);
return new TessellatedModel(out.build(), shadeSeparated);
}
}

View file

@ -2,9 +2,9 @@ package com.jozufozu.flywheel.lib.model.baked;
import java.util.function.BiFunction;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Mesh;
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;
@ -67,7 +67,7 @@ public class BlockModelBuilder {
materialFunc = ModelUtil::getMaterial;
}
ImmutableMap.Builder<Material, Mesh> meshMapBuilder = ImmutableMap.builder();
var out = ImmutableList.<Model.ConfiguredMesh>builder();
if (shadeSeparated) {
ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, data) -> {
@ -75,7 +75,8 @@ public class BlockModelBuilder {
if (material != null) {
VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
meshMapBuilder.put(material, 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));
}
};
BakedModelBufferer.bufferBlockShadeSeparated(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, modelData, resultConsumer);
@ -85,12 +86,13 @@ public class BlockModelBuilder {
if (material != null) {
VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
meshMapBuilder.put(material, new SimpleMesh(vertexView, meshData, "source=BlockModelBuilder," + "blockState=" + state + ",renderType=" + renderType));
var mesh = new SimpleMesh(vertexView, meshData, "source=BlockModelBuilder," + "blockState=" + state + ",renderType=" + renderType);
out.add(new Model.ConfiguredMesh(material, mesh));
}
};
BakedModelBufferer.bufferBlock(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, modelData, resultConsumer);
}
return new TessellatedModel(meshMapBuilder.build(), shadeSeparated);
return new TessellatedModel(out.build(), shadeSeparated);
}
}

View file

@ -5,9 +5,9 @@ import java.util.Collections;
import java.util.Map;
import java.util.function.BiFunction;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Mesh;
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;
@ -71,7 +71,7 @@ public class MultiBlockModelBuilder {
materialFunc = ModelUtil::getMaterial;
}
ImmutableMap.Builder<Material, Mesh> meshMapBuilder = ImmutableMap.builder();
var out = ImmutableList.<Model.ConfiguredMesh>builder();
if (shadeSeparated) {
ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, data) -> {
@ -79,7 +79,8 @@ public class MultiBlockModelBuilder {
if (material != null) {
VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
meshMapBuilder.put(material, 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));
}
};
BakedModelBufferer.bufferMultiBlockShadeSeparated(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, modelDataMap, resultConsumer);
@ -89,12 +90,13 @@ public class MultiBlockModelBuilder {
if (material != null) {
VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
meshMapBuilder.put(material, new SimpleMesh(vertexView, meshData, "source=MultiBlockModelBuilder," + "renderType=" + renderType));
var mesh = new SimpleMesh(vertexView, meshData, "source=MultiBlockModelBuilder," + "renderType=" + renderType);
out.add(new Model.ConfiguredMesh(material, mesh));
}
};
BakedModelBufferer.bufferMultiBlock(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, modelDataMap, resultConsumer);
}
return new TessellatedModel(meshMapBuilder.build(), shadeSeparated);
return new TessellatedModel(out.build(), shadeSeparated);
}
}

View file

@ -1,14 +1,12 @@
package com.jozufozu.flywheel.lib.model.baked;
import com.google.common.collect.ImmutableMap;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Mesh;
import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.lib.model.SimpleModel;
public class TessellatedModel extends SimpleModel {
private final boolean shadeSeparated;
public TessellatedModel(ImmutableMap<Material, Mesh> meshes, boolean shadeSeparated) {
public TessellatedModel(ImmutableList<ConfiguredMesh> meshes, boolean shadeSeparated) {
super(meshes);
this.shadeSeparated = shadeSeparated;
}