mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-11-10 20:11:35 +01:00
Better instance deletions.
- Defer element removal until just before the model is drawn. - Use a modified version of ArrayList#removeIf to delete the instances and adjust the keys.
This commit is contained in:
parent
9d77f85b94
commit
fe492c5d75
1 changed files with 53 additions and 19 deletions
|
@ -2,7 +2,7 @@ package com.simibubi.create.foundation.render.backend.instancing;
|
|||
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.simibubi.create.foundation.render.backend.Backend;
|
||||
|
@ -74,18 +74,6 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
|
|||
public synchronized void deleteInstance(InstanceKey<D> key) {
|
||||
verifyKey(key);
|
||||
|
||||
int index = key.index;
|
||||
|
||||
keys.remove(index);
|
||||
data.remove(index);
|
||||
|
||||
for (int i = index; i < keys.size(); i++) {
|
||||
keys.get(i).index--;
|
||||
}
|
||||
|
||||
maxIndexChanged = keys.size() - 1;
|
||||
markIndexChanged(Math.min(maxIndexChanged, index));
|
||||
|
||||
key.invalidate();
|
||||
}
|
||||
|
||||
|
@ -120,7 +108,9 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
|
|||
}
|
||||
|
||||
protected void renderSetup() {
|
||||
if (minIndexChanged < 0 || data.isEmpty()) return;
|
||||
boolean anyRemoved = doRemoval();
|
||||
|
||||
if (!anyRemoved && (minIndexChanged < 0 || data.isEmpty())) return;
|
||||
|
||||
VertexFormat instanceFormat = getInstanceFormat();
|
||||
|
||||
|
@ -140,11 +130,13 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
|
|||
int offset = minIndexChanged * stride;
|
||||
int length = (1 + maxIndexChanged - minIndexChanged) * stride;
|
||||
|
||||
vbo.map(offset, length, buffer -> {
|
||||
for (int i = minIndexChanged; i <= maxIndexChanged; i++) {
|
||||
data.get(i).write(buffer);
|
||||
}
|
||||
});
|
||||
if (length > 0) {
|
||||
vbo.map(offset, length, buffer -> {
|
||||
for (int i = minIndexChanged; i <= maxIndexChanged; i++) {
|
||||
data.get(i).write(buffer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (newInstanceCount < glInstanceCount) {
|
||||
int clearFrom = (maxIndexChanged + 1) * stride;
|
||||
|
@ -170,6 +162,48 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
|
|||
maxIndexChanged = -1;
|
||||
}
|
||||
|
||||
// copied from ArrayList#removeIf
|
||||
protected boolean doRemoval() {
|
||||
// figure out which elements are to be removed
|
||||
// any exception thrown from the filter predicate at this stage
|
||||
// will leave the collection unmodified
|
||||
int removeCount = 0;
|
||||
final int size = this.keys.size();
|
||||
final BitSet removeSet = new BitSet(size);
|
||||
for (int i=0; i < size; i++) {
|
||||
final InstanceKey<D> element = this.keys.get(i);
|
||||
if (!element.isValid()) {
|
||||
removeSet.set(i);
|
||||
removeCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// shift surviving elements left over the spaces left by removed elements
|
||||
final boolean anyToRemove = removeCount > 0;
|
||||
if (anyToRemove) {
|
||||
final int newSize = size - removeCount;
|
||||
for (int i = 0, j = 0; (i < size) && (j < newSize); i++, j++) {
|
||||
i = removeSet.nextClearBit(i);
|
||||
keys.set(j, keys.get(i));
|
||||
data.set(j, data.get(i));
|
||||
}
|
||||
|
||||
keys.subList(newSize, size).clear();
|
||||
data.subList(newSize, size).clear();
|
||||
|
||||
int firstChanged = removeSet.nextSetBit(0);
|
||||
|
||||
for (int i = firstChanged; i < newSize; i++) {
|
||||
keys.get(i).index = i;
|
||||
}
|
||||
|
||||
minIndexChanged = 0;
|
||||
maxIndexChanged = newSize - 1;
|
||||
}
|
||||
|
||||
return anyToRemove;
|
||||
}
|
||||
|
||||
protected void markIndexChanged(int index) {
|
||||
if (minIndexChanged < 0) {
|
||||
minIndexChanged = index;
|
||||
|
|
Loading…
Reference in a new issue