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; package com.jozufozu.flywheel.api.model;
import java.util.Map; import java.util.List;
import org.joml.Vector4fc; import org.joml.Vector4fc;
import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.material.Material;
public interface Model { 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). * 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(); Vector4fc boundingSphere();
// TODO: unused. remove?
@Deprecated
int vertexCount();
void delete(); void delete();
record ConfiguredMesh(Material material, Mesh mesh) {
}
} }

View file

@ -118,13 +118,13 @@ public class MeshPool {
mesh.byteIndex = byteIndex; mesh.byteIndex = byteIndex;
mesh.baseVertex = baseVertex; mesh.baseVertex = baseVertex;
mesh.write(vertexPtr, vertexView); vertexView.ptr(vertexPtr + mesh.byteIndex);
vertexView.vertexCount(mesh.vertexCount);
mesh.mesh.write(vertexView);
byteIndex += mesh.byteSize(); byteIndex += mesh.byteSize();
baseVertex += mesh.vertexCount(); baseVertex += mesh.vertexCount();
mesh.firstIndex = indexPool.firstIndex(mesh.mesh.indexSequence());
mesh.boundTo.clear(); mesh.boundTo.clear();
} }
@ -153,7 +153,6 @@ public class MeshPool {
private long byteIndex; private long byteIndex;
private int baseVertex; private int baseVertex;
private int firstIndex;
private int referenceCount = 0; private int referenceCount = 0;
private final Set<GlVertexArray> boundTo = new ReferenceArraySet<>(); private final Set<GlVertexArray> boundTo = new ReferenceArraySet<>();
@ -181,7 +180,7 @@ public class MeshPool {
} }
public int firstIndex() { public int firstIndex() {
return firstIndex; return indexPool.firstIndex(mesh.indexSequence());
} }
public boolean deleted() { public boolean deleted() {
@ -192,17 +191,11 @@ public class MeshPool {
return mesh.vertexCount() == 0 || deleted() || byteIndex == -1; 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) { public void draw(int instanceCount) {
if (instanceCount > 1) { 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 { } 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.Instance;
import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.material.Material; 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.model.Model;
import com.jozufozu.flywheel.backend.compile.IndirectPrograms; import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
import com.jozufozu.flywheel.backend.engine.MaterialRenderState; import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
@ -182,9 +181,9 @@ public class IndirectCullingGroup<I extends Instance> {
instancer.index = instancers.size(); instancer.index = instancers.size();
instancers.add(instancer); instancers.add(instancer);
for (Map.Entry<Material, Mesh> entry : model.meshes().entrySet()) { for (var entry : model.meshes()) {
MeshPool.BufferedMesh bufferedMesh = meshPool.alloc(entry.getValue()); MeshPool.BufferedMesh bufferedMesh = meshPool.alloc(entry.mesh());
var draw = new IndirectDraw(instancer, entry.getKey(), bufferedMesh, stage); var draw = new IndirectDraw(instancer, entry.material(), bufferedMesh, stage);
indirectDraws.add(draw); indirectDraws.add(draw);
instancer.addDraw(draw); instancer.addDraw(draw);
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -2,9 +2,9 @@ package com.jozufozu.flywheel.lib.model.baked;
import java.util.function.BiFunction; 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.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.api.vertex.VertexView;
import com.jozufozu.flywheel.lib.memory.MemoryBlock; import com.jozufozu.flywheel.lib.memory.MemoryBlock;
import com.jozufozu.flywheel.lib.model.ModelUtil; import com.jozufozu.flywheel.lib.model.ModelUtil;
@ -78,7 +78,7 @@ public class BakedModelBuilder {
materialFunc = ModelUtil::getMaterial; materialFunc = ModelUtil::getMaterial;
} }
ImmutableMap.Builder<Material, Mesh> meshMapBuilder = ImmutableMap.builder(); var out = ImmutableList.<Model.ConfiguredMesh>builder();
if (shadeSeparated) { if (shadeSeparated) {
ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, data) -> { ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, data) -> {
@ -86,7 +86,8 @@ public class BakedModelBuilder {
if (material != null) { if (material != null) {
VertexView vertexView = new NoOverlayVertexView(); VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView); 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); BakedModelBufferer.bufferSingleShadeSeparated(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, modelData, resultConsumer);
@ -96,12 +97,13 @@ public class BakedModelBuilder {
if (material != null) { if (material != null) {
VertexView vertexView = new NoOverlayVertexView(); VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView); 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); 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 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.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.api.vertex.VertexView;
import com.jozufozu.flywheel.lib.memory.MemoryBlock; import com.jozufozu.flywheel.lib.memory.MemoryBlock;
import com.jozufozu.flywheel.lib.model.ModelUtil; import com.jozufozu.flywheel.lib.model.ModelUtil;
@ -67,7 +67,7 @@ public class BlockModelBuilder {
materialFunc = ModelUtil::getMaterial; materialFunc = ModelUtil::getMaterial;
} }
ImmutableMap.Builder<Material, Mesh> meshMapBuilder = ImmutableMap.builder(); var out = ImmutableList.<Model.ConfiguredMesh>builder();
if (shadeSeparated) { if (shadeSeparated) {
ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, data) -> { ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, data) -> {
@ -75,7 +75,8 @@ public class BlockModelBuilder {
if (material != null) { if (material != null) {
VertexView vertexView = new NoOverlayVertexView(); VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView); 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); BakedModelBufferer.bufferBlockShadeSeparated(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, modelData, resultConsumer);
@ -85,12 +86,13 @@ public class BlockModelBuilder {
if (material != null) { if (material != null) {
VertexView vertexView = new NoOverlayVertexView(); VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView); 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); 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.Map;
import java.util.function.BiFunction; 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.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.api.vertex.VertexView;
import com.jozufozu.flywheel.lib.memory.MemoryBlock; import com.jozufozu.flywheel.lib.memory.MemoryBlock;
import com.jozufozu.flywheel.lib.model.ModelUtil; import com.jozufozu.flywheel.lib.model.ModelUtil;
@ -71,7 +71,7 @@ public class MultiBlockModelBuilder {
materialFunc = ModelUtil::getMaterial; materialFunc = ModelUtil::getMaterial;
} }
ImmutableMap.Builder<Material, Mesh> meshMapBuilder = ImmutableMap.builder(); var out = ImmutableList.<Model.ConfiguredMesh>builder();
if (shadeSeparated) { if (shadeSeparated) {
ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, data) -> { ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, data) -> {
@ -79,7 +79,8 @@ public class MultiBlockModelBuilder {
if (material != null) { if (material != null) {
VertexView vertexView = new NoOverlayVertexView(); VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView); 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); BakedModelBufferer.bufferMultiBlockShadeSeparated(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, modelDataMap, resultConsumer);
@ -89,12 +90,13 @@ public class MultiBlockModelBuilder {
if (material != null) { if (material != null) {
VertexView vertexView = new NoOverlayVertexView(); VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView); 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); 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; package com.jozufozu.flywheel.lib.model.baked;
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.lib.model.SimpleModel; import com.jozufozu.flywheel.lib.model.SimpleModel;
public class TessellatedModel extends SimpleModel { public class TessellatedModel extends SimpleModel {
private final boolean shadeSeparated; private final boolean shadeSeparated;
public TessellatedModel(ImmutableMap<Material, Mesh> meshes, boolean shadeSeparated) { public TessellatedModel(ImmutableList<ConfiguredMesh> meshes, boolean shadeSeparated) {
super(meshes); super(meshes);
this.shadeSeparated = shadeSeparated; this.shadeSeparated = shadeSeparated;
} }