diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/GPUInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/GPUInstancer.java new file mode 100644 index 000000000..51ce4d700 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/GPUInstancer.java @@ -0,0 +1,325 @@ +package com.jozufozu.flywheel.backend.instancing; + +import java.util.ArrayList; +import java.util.BitSet; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.backend.gl.GlVertexArray; +import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat; +import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer; +import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType; +import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer; +import com.jozufozu.flywheel.backend.model.ModelAllocator; +import com.jozufozu.flywheel.backend.model.IBufferedModel; +import com.jozufozu.flywheel.core.model.IModel; +import com.jozufozu.flywheel.util.AttribUtil; + +/** + * An instancer is how you interact with an instanced model. + *

+ * Instanced models can have many copies, and on most systems it's very fast to draw all of the copies at once. + * There is no limit to how many copies an instanced model can have. + * Each copy is represented by an InstanceData object. + *

+ *

+ * When you call {@link #createInstance()} you are given an InstanceData object that you can manipulate however + * you want. The changes you make to the InstanceData object are automatically made visible, and persistent. + * Changing the position of your InstanceData object every frame means that that copy of the model will be in a + * different position in the world each frame. Setting the position of your InstanceData once and not touching it + * again means that your model will be in the same position in the world every frame. This persistence is useful + * because it means the properties of your model don't have to be re-evaluated every frame. + *

+ * + * @param the data that represents a copy of the instanced model. + */ +public class GPUInstancer implements Instancer { + + private final ModelAllocator modelAllocator; + private final IModel modelData; + private final VertexFormat instanceFormat; + private final IInstanceFactory factory; + + private IBufferedModel model; + private GlVertexArray vao; + private GlBuffer instanceVBO; + private int glBufferSize = -1; + private int glInstanceCount = 0; + private boolean deleted; + private boolean initialized; + + private final ArrayList data = new ArrayList<>(); + + boolean anyToRemove; + boolean anyToUpdate; + + public GPUInstancer(ModelAllocator modelAllocator, IModel model, IInstanceFactory factory, VertexFormat instanceFormat) { + this.modelAllocator = modelAllocator; + this.modelData = model; + this.factory = factory; + this.instanceFormat = instanceFormat; + } + + /** + * @return a handle to a new copy of this model. + */ + @Override + public D createInstance() { + return _add(factory.create(this)); + } + + /** + * Copy a data from another Instancer to this. + * + * This has the effect of swapping out one model for another. + * @param inOther the data associated with a different model. + */ + @Override + public void stealInstance(D inOther) { + if (inOther.owner == this) return; + + inOther.delete(); + // sike, we want to keep it, changing the owner reference will still delete it in the other + inOther.removed = false; + _add(inOther); + } + + public void render() { + if (invalid()) return; + + vao.bind(); + renderSetup(); + + if (glInstanceCount > 0) model.drawInstances(glInstanceCount); + + // persistent mapping sync point + instanceVBO.doneForThisFrame(); + + vao.unbind(); + } + + private boolean invalid() { + return deleted || model == null; + } + + public void init() { + if (isInitialized()) return; + + initialized = true; + + vao = new GlVertexArray(); + + model = modelAllocator.alloc(modelData, arenaModel -> { + vao.bind(); + + model.setupState(); + + vao.unbind(); + }); + + vao.bind(); + + instanceVBO = GlBuffer.requestPersistent(GlBufferType.ARRAY_BUFFER); + AttribUtil.enableArrays(model.getAttributeCount() + instanceFormat.getAttributeCount()); + + vao.unbind(); + } + + public boolean isInitialized() { + return initialized; + } + + public boolean isEmpty() { + return !anyToUpdate && !anyToRemove && glInstanceCount == 0; + } + + /** + * Clear all instance data without freeing resources. + */ + public void clear() { + data.clear(); + anyToRemove = true; + } + + /** + * Free acquired resources. All other Instancer methods are undefined behavior after calling delete. + */ + public void delete() { + if (invalid()) return; + + deleted = true; + + model.delete(); + + instanceVBO.delete(); + vao.delete(); + } + + private D _add(D instanceData) { + instanceData.owner = this; + + instanceData.dirty = true; + anyToUpdate = true; + synchronized (data) { + data.add(instanceData); + } + + return instanceData; + } + + protected void renderSetup() { + if (anyToRemove) { + removeDeletedInstances(); + } + + instanceVBO.bind(); + if (!realloc()) { + + if (anyToRemove) { + clearBufferTail(); + } + + if (anyToUpdate) { + updateBuffer(); + } + + glInstanceCount = data.size(); + } + + instanceVBO.unbind(); + + anyToRemove = anyToUpdate = false; + } + + private void clearBufferTail() { + int size = data.size(); + final int offset = size * instanceFormat.getStride(); + final int length = glBufferSize - offset; + if (length > 0) { + instanceVBO.getBuffer(offset, length) + .putByteArray(new byte[length]) + .flush(); + } + } + + private void updateBuffer() { + final int size = data.size(); + + if (size <= 0) return; + + final int stride = instanceFormat.getStride(); + final BitSet dirtySet = getDirtyBitSet(); + + if (dirtySet.isEmpty()) return; + + final int firstDirty = dirtySet.nextSetBit(0); + final int lastDirty = dirtySet.previousSetBit(size); + + final int offset = firstDirty * stride; + final int length = (1 + lastDirty - firstDirty) * stride; + + if (length > 0) { + MappedBuffer mapped = instanceVBO.getBuffer(offset, length); + + dirtySet.stream() + .forEach(i -> { + final D d = data.get(i); + + mapped.position(i * stride); + d.write(mapped); + }); + mapped.flush(); + } + } + + private BitSet getDirtyBitSet() { + final int size = data.size(); + final BitSet dirtySet = new BitSet(size); + + for (int i = 0; i < size; i++) { + D element = data.get(i); + if (element.dirty) { + dirtySet.set(i); + + element.dirty = false; + } + } + return dirtySet; + } + + private boolean realloc() { + int size = this.data.size(); + int stride = instanceFormat.getStride(); + int requiredSize = size * stride; + if (requiredSize > glBufferSize) { + glBufferSize = requiredSize + stride * 16; + instanceVBO.alloc(glBufferSize); + + MappedBuffer buffer = instanceVBO.getBuffer(0, glBufferSize); + for (D datum : data) { + datum.write(buffer); + } + buffer.flush(); + + glInstanceCount = size; + + informAttribDivisors(); + + return true; + } + return false; + } + + private void removeDeletedInstances() { + // Figure out which elements are to be removed. + final int oldSize = this.data.size(); + int removeCount = 0; + final BitSet removeSet = new BitSet(oldSize); + for (int i = 0; i < oldSize; i++) { + final D element = this.data.get(i); + if (element.removed || element.owner != this) { + removeSet.set(i); + removeCount++; + } + } + + final int newSize = oldSize - removeCount; + + // shift surviving elements left over the spaces left by removed elements + for (int i = 0, j = 0; (i < oldSize) && (j < newSize); i++, j++) { + i = removeSet.nextClearBit(i); + + if (i != j) { + D element = data.get(i); + data.set(j, element); + element.dirty = true; + } + } + + anyToUpdate = true; + + data.subList(newSize, oldSize) + .clear(); + + } + + private void informAttribDivisors() { + int staticAttributes = model.getAttributeCount(); + instanceFormat.vertexAttribPointers(staticAttributes); + + for (int i = 0; i < instanceFormat.getAttributeCount(); i++) { + Backend.getInstance().compat.instancedArrays.vertexAttribDivisor(i + staticAttributes, 1); + } + } + + @Override + public void markDirty(InstanceData instanceData) { + anyToUpdate = true; + instanceData.dirty = true; + } + + @Override + public void markRemoval(InstanceData instanceData) { + anyToRemove = true; + instanceData.removed = true; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceData.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceData.java index 21eaed753..a8c1adfa0 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceData.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceData.java @@ -16,13 +16,11 @@ public abstract class InstanceData { public abstract void write(MappedBuffer buf); public void markDirty() { - owner.anyToUpdate = true; - dirty = true; + owner.markDirty(this); } public void delete() { - owner.anyToRemove = true; - removed = true; + owner.markRemoval(this); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java index 1ceaa6953..28737e143 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java @@ -1,71 +1,10 @@ package com.jozufozu.flywheel.backend.instancing; -import java.util.ArrayList; -import java.util.BitSet; - -import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.gl.GlVertexArray; -import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat; -import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer; -import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType; -import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer; -import com.jozufozu.flywheel.backend.material.MaterialSpec; -import com.jozufozu.flywheel.backend.model.ModelAllocator; -import com.jozufozu.flywheel.backend.model.IBufferedModel; -import com.jozufozu.flywheel.core.model.IModel; -import com.jozufozu.flywheel.util.AttribUtil; - -/** - * An instancer is how you interact with an instanced model. - *

- * Instanced models can have many copies, and on most systems it's very fast to draw all of the copies at once. - * There is no limit to how many copies an instanced model can have. - * Each copy is represented by an InstanceData object. - *

- *

- * When you call {@link #createInstance()} you are given an InstanceData object that you can manipulate however - * you want. The changes you make to the InstanceData object are automatically made visible, and persistent. - * Changing the position of your InstanceData object every frame means that that copy of the model will be in a - * different position in the world each frame. Setting the position of your InstanceData once and not touching it - * again means that your model will be in the same position in the world every frame. This persistence is useful - * because it means the properties of your model don't have to be re-evaluated every frame. - *

- * - * @param the data that represents a copy of the instanced model. - */ -public class Instancer { - - private final ModelAllocator modelAllocator; - private final IModel modelData; - private final VertexFormat instanceFormat; - private final IInstanceFactory factory; - - private IBufferedModel model; - private GlVertexArray vao; - private GlBuffer instanceVBO; - private int glBufferSize = -1; - private int glInstanceCount = 0; - private boolean deleted; - private boolean initialized; - - private final ArrayList data = new ArrayList<>(); - - boolean anyToRemove; - boolean anyToUpdate; - - public Instancer(ModelAllocator modelAllocator, IModel model, IInstanceFactory factory, VertexFormat instanceFormat) { - this.modelAllocator = modelAllocator; - this.modelData = model; - this.factory = factory; - this.instanceFormat = instanceFormat; - } - +public interface Instancer { /** * @return a handle to a new copy of this model. */ - public D createInstance() { - return _add(factory.create(this)); - } + D createInstance(); /** * Copy a data from another Instancer to this. @@ -73,239 +12,9 @@ public class Instancer { * This has the effect of swapping out one model for another. * @param inOther the data associated with a different model. */ - public void stealInstance(D inOther) { - if (inOther.owner == this) return; + void stealInstance(D inOther); - inOther.owner.anyToRemove = true; - _add(inOther); - } - - public void render() { - if (invalid()) return; - - vao.bind(); - renderSetup(); - - if (glInstanceCount > 0) model.drawInstances(glInstanceCount); - - // persistent mapping sync point - instanceVBO.doneForThisFrame(); - - vao.unbind(); - } - - private boolean invalid() { - return deleted || model == null; - } - - public void init() { - if (isInitialized()) return; - - initialized = true; - - vao = new GlVertexArray(); - - model = modelAllocator.alloc(modelData, arenaModel -> { - vao.bind(); - - model.setupState(); - - vao.unbind(); - }); - - vao.bind(); - - instanceVBO = GlBuffer.requestPersistent(GlBufferType.ARRAY_BUFFER); - AttribUtil.enableArrays(model.getAttributeCount() + instanceFormat.getAttributeCount()); - - vao.unbind(); - } - - public boolean isInitialized() { - return initialized; - } - - public boolean isEmpty() { - return !anyToUpdate && !anyToRemove && glInstanceCount == 0; - } - - /** - * Clear all instance data without freeing resources. - */ - public void clear() { - data.clear(); - anyToRemove = true; - } - - /** - * Free acquired resources. All other Instancer methods are undefined behavior after calling delete. - */ - public void delete() { - if (invalid()) return; - - deleted = true; - - model.delete(); - - instanceVBO.delete(); - vao.delete(); - } - - private D _add(D instanceData) { - instanceData.owner = this; - - instanceData.dirty = true; - anyToUpdate = true; - synchronized (data) { - data.add(instanceData); - } - - return instanceData; - } - - protected void renderSetup() { - if (anyToRemove) { - removeDeletedInstances(); - } - - instanceVBO.bind(); - if (!realloc()) { - - if (anyToRemove) { - clearBufferTail(); - } - - if (anyToUpdate) { - updateBuffer(); - } - - glInstanceCount = data.size(); - } - - instanceVBO.unbind(); - - anyToRemove = anyToUpdate = false; - } - - private void clearBufferTail() { - int size = data.size(); - final int offset = size * instanceFormat.getStride(); - final int length = glBufferSize - offset; - if (length > 0) { - instanceVBO.getBuffer(offset, length) - .putByteArray(new byte[length]) - .flush(); - } - } - - private void updateBuffer() { - final int size = data.size(); - - if (size <= 0) return; - - final int stride = instanceFormat.getStride(); - final BitSet dirtySet = getDirtyBitSet(); - - if (dirtySet.isEmpty()) return; - - final int firstDirty = dirtySet.nextSetBit(0); - final int lastDirty = dirtySet.previousSetBit(size); - - final int offset = firstDirty * stride; - final int length = (1 + lastDirty - firstDirty) * stride; - - if (length > 0) { - MappedBuffer mapped = instanceVBO.getBuffer(offset, length); - - dirtySet.stream() - .forEach(i -> { - final D d = data.get(i); - - mapped.position(i * stride); - d.write(mapped); - }); - mapped.flush(); - } - } - - private BitSet getDirtyBitSet() { - final int size = data.size(); - final BitSet dirtySet = new BitSet(size); - - for (int i = 0; i < size; i++) { - D element = data.get(i); - if (element.dirty) { - dirtySet.set(i); - - element.dirty = false; - } - } - return dirtySet; - } - - private boolean realloc() { - int size = this.data.size(); - int stride = instanceFormat.getStride(); - int requiredSize = size * stride; - if (requiredSize > glBufferSize) { - glBufferSize = requiredSize + stride * 16; - instanceVBO.alloc(glBufferSize); - - MappedBuffer buffer = instanceVBO.getBuffer(0, glBufferSize); - for (D datum : data) { - datum.write(buffer); - } - buffer.flush(); - - glInstanceCount = size; - - informAttribDivisors(); - - return true; - } - return false; - } - - private void removeDeletedInstances() { - // Figure out which elements are to be removed. - final int oldSize = this.data.size(); - int removeCount = 0; - final BitSet removeSet = new BitSet(oldSize); - for (int i = 0; i < oldSize; i++) { - final D element = this.data.get(i); - if (element.removed || element.owner != this) { - removeSet.set(i); - removeCount++; - } - } - - final int newSize = oldSize - removeCount; - - // shift surviving elements left over the spaces left by removed elements - for (int i = 0, j = 0; (i < oldSize) && (j < newSize); i++, j++) { - i = removeSet.nextClearBit(i); - - if (i != j) { - D element = data.get(i); - data.set(j, element); - element.dirty = true; - } - } - - anyToUpdate = true; - - data.subList(newSize, oldSize) - .clear(); - - } - - private void informAttribDivisors() { - int staticAttributes = model.getAttributeCount(); - instanceFormat.vertexAttribPointers(staticAttributes); - - for (int i = 0; i < instanceFormat.getAttributeCount(); i++) { - Backend.getInstance().compat.instancedArrays.vertexAttribDivisor(i + staticAttributes, 1); - } - } + void markDirty(InstanceData instanceData); + void markRemoval(InstanceData instanceData); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/tile/TileEntityInstance.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/tile/TileEntityInstance.java index 45e308032..7ddefdd32 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/tile/TileEntityInstance.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/tile/TileEntityInstance.java @@ -3,7 +3,7 @@ package com.jozufozu.flywheel.backend.instancing.tile; import com.jozufozu.flywheel.backend.instancing.IDynamicInstance; import com.jozufozu.flywheel.backend.instancing.AbstractInstance; import com.jozufozu.flywheel.backend.instancing.ITickableInstance; -import com.jozufozu.flywheel.backend.material.InstanceMaterial; +import com.jozufozu.flywheel.backend.material.Material; import com.jozufozu.flywheel.backend.material.MaterialManager; import com.jozufozu.flywheel.core.Materials; import com.jozufozu.flywheel.core.materials.ModelData; @@ -76,11 +76,11 @@ public abstract class TileEntityInstance extends AbstractI return pos; } - protected InstanceMaterial getTransformMaterial() { + protected Material getTransformMaterial() { return materialManager.defaultCutout().material(Materials.TRANSFORMED); } - protected InstanceMaterial getOrientedMaterial() { + protected Material getOrientedMaterial() { return materialManager.defaultCutout().material(Materials.ORIENTED); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/material/InstanceMaterial.java b/src/main/java/com/jozufozu/flywheel/backend/material/Material.java similarity index 96% rename from src/main/java/com/jozufozu/flywheel/backend/material/InstanceMaterial.java rename to src/main/java/com/jozufozu/flywheel/backend/material/Material.java index 5576d3fb2..db56d012a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/material/InstanceMaterial.java +++ b/src/main/java/com/jozufozu/flywheel/backend/material/Material.java @@ -14,7 +14,7 @@ import com.mojang.blaze3d.matrix.MatrixStack; import net.minecraft.block.BlockState; import net.minecraft.util.Direction; -public interface InstanceMaterial { +public interface Material { /** * Get an instancer for the given model. Calling this method twice with the same key will return the same instancer. * diff --git a/src/main/java/com/jozufozu/flywheel/backend/material/MaterialGroup.java b/src/main/java/com/jozufozu/flywheel/backend/material/MaterialGroup.java index ac2e4d6cd..2e3bb81fe 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/material/MaterialGroup.java +++ b/src/main/java/com/jozufozu/flywheel/backend/material/MaterialGroup.java @@ -10,5 +10,5 @@ public interface MaterialGroup { * @param The type representing the per instance data. * @return A material you can use to render models. */ - InstanceMaterial material(MaterialSpec spec); + Material material(MaterialSpec spec); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/material/MaterialGroupImpl.java b/src/main/java/com/jozufozu/flywheel/backend/material/MaterialGroupImpl.java index 3c6ab0a32..0f3661929 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/material/MaterialGroupImpl.java +++ b/src/main/java/com/jozufozu/flywheel/backend/material/MaterialGroupImpl.java @@ -23,7 +23,7 @@ public class MaterialGroupImpl

implements MaterialGroup private final ArrayList> renderers = new ArrayList<>(); - private final Map, InstanceMaterialImpl> materials = new HashMap<>(); + private final Map, MaterialImpl> materials = new HashMap<>(); public MaterialGroupImpl(MaterialManagerImpl

owner, IRenderState state) { this.owner = owner; @@ -38,8 +38,8 @@ public class MaterialGroupImpl

implements MaterialGroup */ @SuppressWarnings("unchecked") @Override - public InstanceMaterialImpl material(MaterialSpec spec) { - return (InstanceMaterialImpl) materials.computeIfAbsent(spec, this::createInstanceMaterial); + public MaterialImpl material(MaterialSpec spec) { + return (MaterialImpl) materials.computeIfAbsent(spec, this::createInstanceMaterial); } public void render(Matrix4f viewProjection, double camX, double camY, double camZ) { @@ -53,19 +53,19 @@ public class MaterialGroupImpl

implements MaterialGroup } public void clear() { - materials.values().forEach(InstanceMaterialImpl::clear); + materials.values().forEach(MaterialImpl::clear); } public void delete() { materials.values() - .forEach(InstanceMaterialImpl::delete); + .forEach(MaterialImpl::delete); materials.clear(); renderers.clear(); } - private InstanceMaterialImpl createInstanceMaterial(MaterialSpec type) { - InstanceMaterialImpl material = new InstanceMaterialImpl<>(type); + private MaterialImpl createInstanceMaterial(MaterialSpec type) { + MaterialImpl material = new MaterialImpl<>(type); this.renderers.add(new MaterialRenderer<>(owner.getProgram(type.getProgramName()), material, this::setup)); diff --git a/src/main/java/com/jozufozu/flywheel/backend/material/InstanceMaterialImpl.java b/src/main/java/com/jozufozu/flywheel/backend/material/MaterialImpl.java similarity index 77% rename from src/main/java/com/jozufozu/flywheel/backend/material/InstanceMaterialImpl.java rename to src/main/java/com/jozufozu/flywheel/backend/material/MaterialImpl.java index 7f91c98e9..ad0bb535c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/material/InstanceMaterialImpl.java +++ b/src/main/java/com/jozufozu/flywheel/backend/material/MaterialImpl.java @@ -6,6 +6,7 @@ import java.util.function.Supplier; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.jozufozu.flywheel.backend.RenderWork; +import com.jozufozu.flywheel.backend.instancing.GPUInstancer; import com.jozufozu.flywheel.backend.instancing.InstanceData; import com.jozufozu.flywheel.backend.instancing.Instancer; import com.jozufozu.flywheel.backend.model.ModelPool; @@ -15,19 +16,19 @@ import com.jozufozu.flywheel.core.model.IModel; * A collection of Instancers that all have the same format. * @param */ -public class InstanceMaterialImpl implements InstanceMaterial { +public class MaterialImpl implements Material { final ModelPool modelPool; - protected final Cache> models; + protected final Cache> models; protected final MaterialSpec spec; - public InstanceMaterialImpl(MaterialSpec spec) { + public MaterialImpl(MaterialSpec spec) { this.spec = spec; modelPool = new ModelPool(spec.getModelFormat(), spec.getModelFormat().getStride() * 64); this.models = CacheBuilder.newBuilder() .removalListener(notification -> { - Instancer instancer = (Instancer) notification.getValue(); + GPUInstancer instancer = (GPUInstancer) notification.getValue(); RenderWork.enqueue(instancer::delete); }) .build(); @@ -43,7 +44,7 @@ public class InstanceMaterialImpl implements InstanceMat @Override public Instancer model(Object key, Supplier modelSupplier) { try { - return models.get(key, () -> new Instancer<>(modelPool, modelSupplier.get(), spec.getInstanceFactory(), spec.getInstanceFormat())); + return models.get(key, () -> new GPUInstancer<>(modelPool, modelSupplier.get(), spec.getInstanceFactory(), spec.getInstanceFormat())); } catch (ExecutionException e) { throw new RuntimeException("error creating instancer", e); } @@ -53,7 +54,7 @@ public class InstanceMaterialImpl implements InstanceMat return models.size() > 0 && models.asMap() .values() .stream() - .allMatch(Instancer::isEmpty); + .allMatch(GPUInstancer::isEmpty); } public void delete() { @@ -67,7 +68,7 @@ public class InstanceMaterialImpl implements InstanceMat public void clear() { models.asMap() .values() - .forEach(Instancer::clear); + .forEach(GPUInstancer::clear); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/material/MaterialRenderer.java b/src/main/java/com/jozufozu/flywheel/backend/material/MaterialRenderer.java index af695a27c..87ff35494 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/material/MaterialRenderer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/material/MaterialRenderer.java @@ -4,6 +4,7 @@ import java.util.Collection; import java.util.function.Consumer; import java.util.function.Supplier; +import com.jozufozu.flywheel.backend.instancing.GPUInstancer; import com.jozufozu.flywheel.backend.instancing.Instancer; import com.jozufozu.flywheel.core.shader.WorldProgram; @@ -12,11 +13,11 @@ import net.minecraft.util.math.vector.Matrix4f; public class MaterialRenderer

{ protected final Supplier

program; - protected final InstanceMaterialImpl material; + protected final MaterialImpl material; protected final Consumer

setupFunc; - public MaterialRenderer(Supplier

programSupplier, InstanceMaterialImpl material, Consumer

setupFunc) { + public MaterialRenderer(Supplier

programSupplier, MaterialImpl material, Consumer

setupFunc) { this.program = programSupplier; this.material = material; this.setupFunc = setupFunc; @@ -25,11 +26,11 @@ public class MaterialRenderer

{ public void render(Matrix4f viewProjection, double camX, double camY, double camZ) { if (material.nothingToRender()) return; - Collection> instancers = material.models.asMap() + Collection> instancers = material.models.asMap() .values(); // initialize all uninitialized instancers... - instancers.forEach(Instancer::init); + instancers.forEach(GPUInstancer::init); // ...and then flush the model arena in case anything was marked for upload material.modelPool.flush(); @@ -41,7 +42,7 @@ public class MaterialRenderer

{ setupFunc.accept(program); - instancers.forEach(Instancer::render); + instancers.forEach(GPUInstancer::render); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/materials/BasicData.java b/src/main/java/com/jozufozu/flywheel/core/materials/BasicData.java index 2fc7fc285..18f06861e 100644 --- a/src/main/java/com/jozufozu/flywheel/core/materials/BasicData.java +++ b/src/main/java/com/jozufozu/flywheel/core/materials/BasicData.java @@ -1,6 +1,7 @@ package com.jozufozu.flywheel.core.materials; import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer; +import com.jozufozu.flywheel.backend.instancing.GPUInstancer; import com.jozufozu.flywheel.backend.instancing.InstanceData; import com.jozufozu.flywheel.backend.instancing.Instancer; diff --git a/src/main/java/com/jozufozu/flywheel/core/materials/ModelData.java b/src/main/java/com/jozufozu/flywheel/core/materials/ModelData.java index 9c15d99cd..2d5945301 100644 --- a/src/main/java/com/jozufozu/flywheel/core/materials/ModelData.java +++ b/src/main/java/com/jozufozu/flywheel/core/materials/ModelData.java @@ -1,6 +1,7 @@ package com.jozufozu.flywheel.core.materials; import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer; +import com.jozufozu.flywheel.backend.instancing.GPUInstancer; import com.jozufozu.flywheel.backend.instancing.Instancer; import com.jozufozu.flywheel.util.RenderUtil; import com.mojang.blaze3d.matrix.MatrixStack; diff --git a/src/main/java/com/jozufozu/flywheel/core/materials/OrientedData.java b/src/main/java/com/jozufozu/flywheel/core/materials/OrientedData.java index 4a3010abd..657cc8daf 100644 --- a/src/main/java/com/jozufozu/flywheel/core/materials/OrientedData.java +++ b/src/main/java/com/jozufozu/flywheel/core/materials/OrientedData.java @@ -1,6 +1,7 @@ package com.jozufozu.flywheel.core.materials; import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer; +import com.jozufozu.flywheel.backend.instancing.GPUInstancer; import com.jozufozu.flywheel.backend.instancing.Instancer; import com.jozufozu.flywheel.util.vec.Vec3;