mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-06 04:16:36 +01:00
How to handle InstancePart abstraction
- Pull InstancePart into an interface - Add Handle interface to opaquely notify an instancer something has changed or was deleted. - Remove notify* methods from Instancer - Remove stealInstance TODO: find a better way to accomplish that - Track removals/changes through bitsets - Deprecate InstancePart#copy - Move InstanceManager#canCreateInstance to Storage#willAccept
This commit is contained in:
parent
391adfef1a
commit
ab8ab8dbd4
41 changed files with 354 additions and 382 deletions
|
@ -2,10 +2,10 @@ package com.jozufozu.flywheel.api.instance;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
|
||||
public interface BlockEntityInstance<T extends BlockEntity> extends Instance {
|
||||
List<InstancedPart> getCrumblingParts();
|
||||
List<InstancePart> getCrumblingParts();
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package com.jozufozu.flywheel.api.instance;
|
|||
|
||||
import org.joml.FrustumIntersection;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.instancer.Instancer;
|
||||
|
||||
/**
|
||||
|
@ -20,7 +20,7 @@ public interface DynamicInstance extends Instance {
|
|||
* <br>
|
||||
* <em>DISPATCHED IN PARALLEL</em>, don't attempt to mutate anything outside this instance.
|
||||
* <br>
|
||||
* {@link Instancer}/{@link InstancedPart} creation/acquisition is safe here.
|
||||
* {@link Instancer}/{@link InstancePart} creation/acquisition is safe here.
|
||||
*/
|
||||
void beginFrame();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.jozufozu.flywheel.api.instance;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.instancer.Instancer;
|
||||
|
||||
/**
|
||||
|
@ -25,7 +25,7 @@ public interface TickableInstance extends Instance {
|
|||
* Called every tick, and after initialization.<p>
|
||||
* <em>DISPATCHED IN PARALLEL</em>, don't attempt to mutate anything outside of this instance
|
||||
* without proper synchronization.<p>
|
||||
* {@link Instancer}/{@link InstancedPart} creation/acquisition is safe here.
|
||||
* {@link Instancer}/{@link InstancePart} creation/acquisition is safe here.
|
||||
*/
|
||||
void tick();
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package com.jozufozu.flywheel.api.instancer;
|
||||
|
||||
public interface Handle {
|
||||
|
||||
void setChanged();
|
||||
|
||||
void setDeleted();
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.jozufozu.flywheel.api.instancer;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
|
||||
public interface InstancePart {
|
||||
StructType<?> type();
|
||||
|
||||
@Deprecated
|
||||
InstancePart copy(Handle handle);
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package com.jozufozu.flywheel.api.instancer;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
|
||||
public abstract class InstancedPart {
|
||||
|
||||
public final StructType<?> type;
|
||||
private Instancer<?> owner;
|
||||
|
||||
private boolean dirty;
|
||||
private boolean removed;
|
||||
|
||||
protected InstancedPart(StructType<?> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public final void markDirty() {
|
||||
dirty = true;
|
||||
owner.notifyDirty();
|
||||
}
|
||||
|
||||
public final void delete() {
|
||||
removed = true;
|
||||
owner.notifyRemoval();
|
||||
}
|
||||
|
||||
public final boolean checkDirtyAndClear() {
|
||||
boolean wasDirty = dirty;
|
||||
dirty = false;
|
||||
return wasDirty;
|
||||
}
|
||||
|
||||
public final boolean isRemoved() {
|
||||
return removed;
|
||||
}
|
||||
|
||||
public Instancer<?> getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(Instancer<?> owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public abstract InstancedPart copy();
|
||||
}
|
|
@ -16,45 +16,20 @@ package com.jozufozu.flywheel.api.instancer;
|
|||
* because it means the properties of your model don't have to be re-evaluated every frame.
|
||||
* </p>
|
||||
*
|
||||
* @param <D> the data that represents a copy of the instanced model.
|
||||
* @param <P> the data that represents a copy of the instanced model.
|
||||
*/
|
||||
public interface Instancer<D extends InstancedPart> {
|
||||
public interface Instancer<P extends InstancePart> {
|
||||
/**
|
||||
* @return a handle to a new copy of this model.
|
||||
*/
|
||||
D createInstance();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void stealInstance(D inOther);
|
||||
|
||||
/**
|
||||
* Notify the Instancer that some of its data needs updating.
|
||||
*
|
||||
* <p>
|
||||
* This might be ignored, depending on the implementation. For the GPUInstancer, this triggers a scan of all
|
||||
* instances.
|
||||
* </p>
|
||||
*/
|
||||
void notifyDirty();
|
||||
|
||||
/**
|
||||
* Notify the Instances that some of its data should be removed.
|
||||
*
|
||||
* <p>
|
||||
* By the time the next frame is drawn, the instanceData passed will no longer be considered for rendering.
|
||||
* </p>
|
||||
*/
|
||||
void notifyRemoval();
|
||||
P createInstance();
|
||||
|
||||
/**
|
||||
* Populate arr with new instances of this model.
|
||||
*
|
||||
* @param arr An array to fill.
|
||||
*/
|
||||
default void createInstances(D[] arr) {
|
||||
default void createInstances(P[] arr) {
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
arr[i] = createInstance();
|
||||
}
|
||||
|
|
|
@ -10,5 +10,5 @@ public interface InstancerProvider {
|
|||
*
|
||||
* @return An instancer for the given struct type, model, and render stage.
|
||||
*/
|
||||
<D extends InstancedPart> Instancer<D> instancer(StructType<D> type, Model model, RenderStage stage);
|
||||
<P extends InstancePart> Instancer<P> instancer(StructType<P> type, Model model, RenderStage stage);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.jozufozu.flywheel.api.struct;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.Handle;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.layout.BufferLayout;
|
||||
import com.jozufozu.flywheel.api.registry.Registry;
|
||||
import com.jozufozu.flywheel.api.vertex.MutableVertexList;
|
||||
|
@ -11,29 +12,31 @@ import net.minecraft.resources.ResourceLocation;
|
|||
|
||||
/**
|
||||
* A StructType contains metadata for a specific instance struct that Flywheel can interface with.
|
||||
* @param <S> The java representation of the instance struct.
|
||||
*
|
||||
* @param <P> The java representation of the instance struct.
|
||||
*/
|
||||
public interface StructType<S extends InstancedPart> {
|
||||
public interface StructType<P extends InstancePart> {
|
||||
static Registry<StructType<?>> REGISTRY = RegistryImpl.create();
|
||||
|
||||
/**
|
||||
* @param handle A handle that allows you to mark the instance as dirty or deleted.
|
||||
* @return A new, zeroed instance of S.
|
||||
*/
|
||||
S create();
|
||||
P create(Handle handle);
|
||||
|
||||
/**
|
||||
* @return The layout of S when buffered.
|
||||
*/
|
||||
BufferLayout getLayout();
|
||||
|
||||
StructWriter<S> getWriter();
|
||||
StructWriter<P> getWriter();
|
||||
|
||||
ResourceLocation instanceShader();
|
||||
|
||||
VertexTransformer<S> getVertexTransformer();
|
||||
VertexTransformer<P> getVertexTransformer();
|
||||
|
||||
interface VertexTransformer<S extends InstancedPart> {
|
||||
void transform(MutableVertexList vertexList, S struct, ClientLevel level);
|
||||
interface VertexTransformer<P extends InstancePart> {
|
||||
void transform(MutableVertexList vertexList, P struct, ClientLevel level);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
package com.jozufozu.flywheel.api.struct;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
|
||||
/**
|
||||
* StructWriters can quickly consume many instances of S and write them to some memory address.
|
||||
*/
|
||||
public interface StructWriter<S extends InstancedPart> {
|
||||
public interface StructWriter<P extends InstancePart> {
|
||||
/**
|
||||
* Write the given struct to the given memory address.
|
||||
*/
|
||||
void write(final long ptr, final S struct);
|
||||
void write(final long ptr, final P struct);
|
||||
|
||||
}
|
||||
|
|
|
@ -4,18 +4,24 @@ import java.util.ArrayList;
|
|||
import java.util.BitSet;
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.instancer.Instancer;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
|
||||
public abstract class AbstractInstancer<D extends InstancedPart> implements Instancer<D> {
|
||||
public abstract class AbstractInstancer<P extends InstancePart> implements Instancer<P> {
|
||||
|
||||
public final StructType<D> type;
|
||||
protected final ArrayList<D> data = new ArrayList<>();
|
||||
public final StructType<P> type;
|
||||
|
||||
protected boolean anyToRemove;
|
||||
// Lock for all instance data, only needs to be used in methods that may run on the TaskExecutor.
|
||||
protected final Object lock = new Object();
|
||||
protected final ArrayList<P> data = new ArrayList<>();
|
||||
protected final ArrayList<HandleImpl> handles = new ArrayList<>();
|
||||
|
||||
protected AbstractInstancer(StructType<D> type) {
|
||||
// TODO: atomic bitset?
|
||||
protected final BitSet changed = new BitSet();
|
||||
protected final BitSet deleted = new BitSet();
|
||||
|
||||
protected AbstractInstancer(StructType<P> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
@ -23,100 +29,92 @@ public abstract class AbstractInstancer<D extends InstancedPart> implements Inst
|
|||
* @return a handle to a new copy of this model.
|
||||
*/
|
||||
@Override
|
||||
public D createInstance() {
|
||||
return _add(type.create());
|
||||
}
|
||||
public P createInstance() {
|
||||
synchronized (lock) {
|
||||
var i = data.size();
|
||||
var handle = new HandleImpl(this, i);
|
||||
P instanceData = type.create(handle);
|
||||
|
||||
/**
|
||||
* Copy a data from another Instancer to this.
|
||||
* <p>
|
||||
* 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.getOwner() == this) return;
|
||||
|
||||
// Changing the owner reference will delete it in the other instancer
|
||||
inOther.getOwner()
|
||||
.notifyRemoval();
|
||||
_add(inOther);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyRemoval() {
|
||||
anyToRemove = true;
|
||||
data.add(instanceData);
|
||||
handles.add(handle);
|
||||
changed.set(i);
|
||||
return instanceData;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all instance data without freeing resources.
|
||||
*/
|
||||
public void clear() {
|
||||
handles.forEach(HandleImpl::clear);
|
||||
data.clear();
|
||||
anyToRemove = true;
|
||||
handles.clear();
|
||||
changed.clear();
|
||||
deleted.clear();
|
||||
}
|
||||
|
||||
public int getInstanceCount() {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
public List<D> getRange(int start, int end) {
|
||||
public List<P> getRange(int start, int end) {
|
||||
return data.subList(start, end);
|
||||
}
|
||||
|
||||
public List<D> getAll() {
|
||||
public List<P> getAll() {
|
||||
return data;
|
||||
}
|
||||
|
||||
protected 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.isRemoved() || element.getOwner() != this) {
|
||||
removeSet.set(i);
|
||||
removeCount++;
|
||||
}
|
||||
}
|
||||
int removeCount = deleted.cardinality();
|
||||
|
||||
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);
|
||||
i = deleted.nextClearBit(i);
|
||||
|
||||
if (i != j) {
|
||||
D element = data.get(i);
|
||||
var handle = handles.get(i);
|
||||
P element = data.get(i);
|
||||
|
||||
handles.set(j, handle);
|
||||
data.set(j, element);
|
||||
// Marking the data dirty marks us dirty too.
|
||||
// Perhaps there will be some wasted cycles, but the JVM should be able to
|
||||
// generate code that moves the repeated segment out of the loop.
|
||||
element.markDirty();
|
||||
|
||||
handle.setIndex(j);
|
||||
changed.set(j);
|
||||
}
|
||||
}
|
||||
|
||||
deleted.clear();
|
||||
data.subList(newSize, oldSize)
|
||||
.clear();
|
||||
|
||||
handles.subList(newSize, oldSize)
|
||||
.clear();
|
||||
}
|
||||
|
||||
private D _add(D instanceData) {
|
||||
instanceData.setOwner(this);
|
||||
|
||||
instanceData.markDirty();
|
||||
synchronized (data) {
|
||||
data.add(instanceData);
|
||||
}
|
||||
|
||||
return instanceData;
|
||||
}
|
||||
|
||||
public abstract void delete();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Instancer[" + getInstanceCount() + ']';
|
||||
}
|
||||
|
||||
public void notifyDirty(int index) {
|
||||
if (index < 0 || index >= getInstanceCount()) {
|
||||
return;
|
||||
}
|
||||
synchronized (lock) {
|
||||
changed.set(index);
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyRemoval(int index) {
|
||||
if (index < 0 || index >= getInstanceCount()) {
|
||||
return;
|
||||
}
|
||||
synchronized (lock) {
|
||||
deleted.set(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package com.jozufozu.flywheel.backend.engine;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.Handle;
|
||||
|
||||
public class HandleImpl implements Handle {
|
||||
|
||||
private final AbstractInstancer<?> instancer;
|
||||
private int index;
|
||||
|
||||
public HandleImpl(AbstractInstancer<?> instancer, int index) {
|
||||
this.instancer = instancer;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChanged() {
|
||||
instancer.notifyDirty(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeleted() {
|
||||
instancer.notifyRemoval(index);
|
||||
}
|
||||
|
||||
public void setIndex(int i) {
|
||||
index = i;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
index = -1;
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
package com.jozufozu.flywheel.backend.engine;
|
||||
|
||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.model.Model;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
|
||||
public record InstancerKey<D extends InstancedPart>(StructType<D> type, Model model, RenderStage stage) {
|
||||
public record InstancerKey<P extends InstancePart>(StructType<P> type, Model model, RenderStage stage) {
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import java.util.List;
|
|||
import com.jozufozu.flywheel.api.backend.Engine;
|
||||
import com.jozufozu.flywheel.api.event.RenderContext;
|
||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.instancer.Instancer;
|
||||
import com.jozufozu.flywheel.api.model.Model;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
|
@ -24,7 +24,7 @@ public class BatchingEngine implements Engine {
|
|||
private final BatchingDrawTracker drawTracker = new BatchingDrawTracker();
|
||||
|
||||
@Override
|
||||
public <D extends InstancedPart> Instancer<D> instancer(StructType<D> type, Model model, RenderStage stage) {
|
||||
public <P extends InstancePart> Instancer<P> instancer(StructType<P> type, Model model, RenderStage stage) {
|
||||
return transformManager.getInstancer(type, model, stage);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import com.google.common.collect.ArrayListMultimap;
|
|||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.instancer.Instancer;
|
||||
import com.jozufozu.flywheel.api.model.Mesh;
|
||||
import com.jozufozu.flywheel.api.model.Model;
|
||||
|
@ -42,9 +42,9 @@ public class BatchingTransformManager {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <D extends InstancedPart> Instancer<D> getInstancer(StructType<D> type, Model model, RenderStage stage) {
|
||||
InstancerKey<D> key = new InstancerKey<>(type, model, stage);
|
||||
CPUInstancer<D> instancer = (CPUInstancer<D>) instancers.get(key);
|
||||
public <P extends InstancePart> Instancer<P> getInstancer(StructType<P> type, Model model, RenderStage stage) {
|
||||
InstancerKey<P> key = new InstancerKey<>(type, model, stage);
|
||||
CPUInstancer<P> instancer = (CPUInstancer<P>) instancers.get(key);
|
||||
if (instancer == null) {
|
||||
instancer = new CPUInstancer<>(type);
|
||||
instancers.put(key, instancer);
|
||||
|
@ -71,7 +71,6 @@ public class BatchingTransformManager {
|
|||
.forEach(BatchedMeshPool::delete);
|
||||
meshPools.clear();
|
||||
|
||||
initializedInstancers.forEach(CPUInstancer::delete);
|
||||
initializedInstancers.clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,29 +1,18 @@
|
|||
package com.jozufozu.flywheel.backend.engine.batching;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
|
||||
|
||||
public class CPUInstancer<D extends InstancedPart> extends AbstractInstancer<D> {
|
||||
public class CPUInstancer<P extends InstancePart> extends AbstractInstancer<P> {
|
||||
|
||||
public CPUInstancer(StructType<D> type) {
|
||||
public CPUInstancer(StructType<P> type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
void update() {
|
||||
if (anyToRemove) {
|
||||
data.removeIf(InstancedPart::isRemoved);
|
||||
anyToRemove = false;
|
||||
if (!deleted.isEmpty()) {
|
||||
removeDeletedInstances();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDirty() {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package com.jozufozu.flywheel.backend.engine.batching;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.task.TaskExecutor;
|
||||
|
@ -16,15 +16,15 @@ import com.mojang.math.Vector4f;
|
|||
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
|
||||
public class TransformCall<D extends InstancedPart> {
|
||||
private final CPUInstancer<D> instancer;
|
||||
public class TransformCall<P extends InstancePart> {
|
||||
private final CPUInstancer<P> instancer;
|
||||
private final Material material;
|
||||
private final BatchedMeshPool.BufferedMesh mesh;
|
||||
|
||||
private final int meshVertexCount;
|
||||
private final int meshByteSize;
|
||||
|
||||
public TransformCall(CPUInstancer<D> instancer, Material material, BatchedMeshPool.BufferedMesh mesh) {
|
||||
public TransformCall(CPUInstancer<P> instancer, Material material, BatchedMeshPool.BufferedMesh mesh) {
|
||||
this.instancer = instancer;
|
||||
this.material = material;
|
||||
this.mesh = mesh;
|
||||
|
@ -65,18 +65,18 @@ public class TransformCall<D extends InstancedPart> {
|
|||
transformList(vertexList, instancer.getAll(), matrices, level);
|
||||
}
|
||||
|
||||
private void transformList(ReusableVertexList vertexList, List<D> parts, PoseStack.Pose matrices, ClientLevel level) {
|
||||
private void transformList(ReusableVertexList vertexList, List<P> parts, PoseStack.Pose matrices, ClientLevel level) {
|
||||
long anchorPtr = vertexList.ptr();
|
||||
int totalVertexCount = vertexList.vertexCount();
|
||||
|
||||
vertexList.vertexCount(meshVertexCount);
|
||||
|
||||
StructType.VertexTransformer<D> structVertexTransformer = instancer.type.getVertexTransformer();
|
||||
StructType.VertexTransformer<P> structVertexTransformer = instancer.type.getVertexTransformer();
|
||||
|
||||
for (D d : parts) {
|
||||
for (P p : parts) {
|
||||
mesh.copyTo(vertexList.ptr());
|
||||
|
||||
structVertexTransformer.transform(vertexList, d, level);
|
||||
structVertexTransformer.transform(vertexList, p, level);
|
||||
|
||||
vertexList.ptr(vertexList.ptr() + meshByteSize);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import static org.lwjgl.opengl.GL45.glVertexArrayElementBuffer;
|
|||
import static org.lwjgl.opengl.GL45.glVertexArrayVertexBuffer;
|
||||
|
||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.compile.FlwCompiler;
|
||||
|
@ -22,7 +22,7 @@ import com.jozufozu.flywheel.lib.context.Contexts;
|
|||
import com.jozufozu.flywheel.lib.pipeline.Pipelines;
|
||||
import com.jozufozu.flywheel.lib.util.QuadConverter;
|
||||
|
||||
public class IndirectCullingGroup<T extends InstancedPart> {
|
||||
public class IndirectCullingGroup<P extends InstancePart> {
|
||||
|
||||
private static final int BARRIER_BITS = GL_SHADER_STORAGE_BARRIER_BIT | GL_COMMAND_BARRIER_BIT;
|
||||
|
||||
|
@ -38,13 +38,13 @@ public class IndirectCullingGroup<T extends InstancedPart> {
|
|||
|
||||
int vertexArray;
|
||||
|
||||
final IndirectDrawSet<T> drawSet = new IndirectDrawSet<>();
|
||||
final IndirectDrawSet<P> drawSet = new IndirectDrawSet<>();
|
||||
|
||||
private boolean hasCulledThisFrame;
|
||||
private boolean needsMemoryBarrier;
|
||||
private int instanceCountThisFrame;
|
||||
|
||||
IndirectCullingGroup(StructType<T> structType, VertexType vertexType) {
|
||||
IndirectCullingGroup(StructType<P> structType, VertexType vertexType) {
|
||||
this.vertexType = vertexType;
|
||||
|
||||
objectStride = structType.getLayout()
|
||||
|
|
|
@ -3,12 +3,12 @@ package com.jozufozu.flywheel.backend.engine.indirect;
|
|||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.lib.material.MaterialIndices;
|
||||
|
||||
public final class IndirectDraw<T extends InstancedPart> {
|
||||
private final IndirectInstancer<T> instancer;
|
||||
public final class IndirectDraw<P extends InstancePart> {
|
||||
private final IndirectInstancer<P> instancer;
|
||||
private final IndirectMeshPool.BufferedMesh mesh;
|
||||
private final Material material;
|
||||
private final RenderStage stage;
|
||||
|
@ -19,7 +19,7 @@ public final class IndirectDraw<T extends InstancedPart> {
|
|||
|
||||
boolean needsFullWrite = true;
|
||||
|
||||
IndirectDraw(IndirectInstancer<T> instancer, Material material, RenderStage stage, IndirectMeshPool.BufferedMesh mesh) {
|
||||
IndirectDraw(IndirectInstancer<P> instancer, Material material, RenderStage stage, IndirectMeshPool.BufferedMesh mesh) {
|
||||
this.instancer = instancer;
|
||||
this.material = material;
|
||||
this.stage = stage;
|
||||
|
@ -42,10 +42,9 @@ public final class IndirectDraw<T extends InstancedPart> {
|
|||
void writeObjects(long objectPtr, long batchIDPtr, int batchID) {
|
||||
if (needsFullWrite) {
|
||||
instancer.writeFull(objectPtr, batchIDPtr, batchID);
|
||||
} else if (instancer.anyToUpdate) {
|
||||
} else {
|
||||
instancer.writeSparse(objectPtr, batchIDPtr, batchID);
|
||||
}
|
||||
instancer.anyToUpdate = false;
|
||||
}
|
||||
|
||||
public void writeIndirectCommand(long ptr) {
|
||||
|
@ -63,7 +62,7 @@ public final class IndirectDraw<T extends InstancedPart> {
|
|||
|
||||
}
|
||||
|
||||
public IndirectInstancer<T> instancer() {
|
||||
public IndirectInstancer<P> instancer() {
|
||||
return instancer;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.instancer.Instancer;
|
||||
import com.jozufozu.flywheel.api.model.Model;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
|
@ -22,9 +22,9 @@ public class IndirectDrawManager {
|
|||
public final Map<Pair<StructType<?>, VertexType>, IndirectCullingGroup<?>> renderLists = new HashMap<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <D extends InstancedPart> Instancer<D> getInstancer(StructType<D> type, Model model, RenderStage stage) {
|
||||
InstancerKey<D> key = new InstancerKey<>(type, model, stage);
|
||||
IndirectInstancer<D> instancer = (IndirectInstancer<D>) instancers.get(key);
|
||||
public <P extends InstancePart> Instancer<P> getInstancer(StructType<P> type, Model model, RenderStage stage) {
|
||||
InstancerKey<P> key = new InstancerKey<>(type, model, stage);
|
||||
IndirectInstancer<P> instancer = (IndirectInstancer<P>) instancers.get(key);
|
||||
if (instancer == null) {
|
||||
instancer = new IndirectInstancer<>(type);
|
||||
instancers.put(key, instancer);
|
||||
|
@ -51,7 +51,6 @@ public class IndirectDrawManager {
|
|||
.forEach(IndirectCullingGroup::delete);
|
||||
renderLists.clear();
|
||||
|
||||
initializedInstancers.forEach(IndirectInstancer::delete);
|
||||
initializedInstancers.clear();
|
||||
}
|
||||
|
||||
|
@ -60,13 +59,13 @@ public class IndirectDrawManager {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <D extends InstancedPart> void add(IndirectInstancer<D> instancer, Model model, RenderStage stage) {
|
||||
private <P extends InstancePart> void add(IndirectInstancer<P> instancer, Model model, RenderStage stage) {
|
||||
var meshes = model.getMeshes();
|
||||
for (var entry : meshes.entrySet()) {
|
||||
var material = entry.getKey();
|
||||
var mesh = entry.getValue();
|
||||
|
||||
var indirectList = (IndirectCullingGroup<D>) renderLists.computeIfAbsent(Pair.of(instancer.type, mesh.getVertexType()), p -> new IndirectCullingGroup<>(p.first(), p.second()));
|
||||
var indirectList = (IndirectCullingGroup<P>) renderLists.computeIfAbsent(Pair.of(instancer.type, mesh.getVertexType()), p -> new IndirectCullingGroup<>(p.first(), p.second()));
|
||||
|
||||
indirectList.drawSet.add(instancer, material, stage, indirectList.meshPool.alloc(mesh));
|
||||
|
||||
|
|
|
@ -11,14 +11,14 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.lib.material.MaterialIndices;
|
||||
import com.jozufozu.flywheel.util.Textures;
|
||||
|
||||
public class IndirectDrawSet<T extends InstancedPart> {
|
||||
public class IndirectDrawSet<P extends InstancePart> {
|
||||
|
||||
final List<IndirectDraw<T>> indirectDraws = new ArrayList<>();
|
||||
final List<IndirectDraw<P>> indirectDraws = new ArrayList<>();
|
||||
|
||||
final Map<RenderStage, List<MultiDraw>> multiDraws = new EnumMap<>(RenderStage.class);
|
||||
|
||||
|
@ -30,7 +30,7 @@ public class IndirectDrawSet<T extends InstancedPart> {
|
|||
return indirectDraws.size();
|
||||
}
|
||||
|
||||
public void add(IndirectInstancer<T> instancer, Material material, RenderStage stage, IndirectMeshPool.BufferedMesh bufferedMesh) {
|
||||
public void add(IndirectInstancer<P> instancer, Material material, RenderStage stage, IndirectMeshPool.BufferedMesh bufferedMesh) {
|
||||
indirectDraws.add(new IndirectDraw<>(instancer, material, stage, bufferedMesh));
|
||||
determineMultiDraws();
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ public class IndirectDrawSet<T extends InstancedPart> {
|
|||
// TODO: Better material equality. Really we only need to bin by the results of the setup method.
|
||||
multiDraws.clear();
|
||||
// sort by stage, then material
|
||||
indirectDraws.sort(Comparator.comparing(IndirectDraw<T>::stage)
|
||||
indirectDraws.sort(Comparator.comparing(IndirectDraw<P>::stage)
|
||||
.thenComparing(draw -> MaterialIndices.getMaterialIndex(draw.material())));
|
||||
|
||||
for (int start = 0, i = 0; i < indirectDraws.size(); i++) {
|
||||
|
|
|
@ -7,7 +7,7 @@ import org.lwjgl.opengl.GL32;
|
|||
import com.jozufozu.flywheel.api.backend.Engine;
|
||||
import com.jozufozu.flywheel.api.event.RenderContext;
|
||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.instancer.Instancer;
|
||||
import com.jozufozu.flywheel.api.model.Model;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
|
@ -34,7 +34,7 @@ public class IndirectEngine implements Engine {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <D extends InstancedPart> Instancer<D> instancer(StructType<D> type, Model model, RenderStage stage) {
|
||||
public <P extends InstancePart> Instancer<P> instancer(StructType<P> type, Model model, RenderStage stage) {
|
||||
return drawManager.getInstancer(type, model, stage);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,54 +2,45 @@ package com.jozufozu.flywheel.backend.engine.indirect;
|
|||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.struct.StructWriter;
|
||||
import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
|
||||
|
||||
public class IndirectInstancer<D extends InstancedPart> extends AbstractInstancer<D> {
|
||||
public class IndirectInstancer<P extends InstancePart> extends AbstractInstancer<P> {
|
||||
|
||||
private final long objectStride;
|
||||
private final StructWriter<D> writer;
|
||||
private final StructWriter<P> writer;
|
||||
int instanceCount = 0;
|
||||
|
||||
boolean anyToUpdate;
|
||||
|
||||
public IndirectInstancer(StructType<D> type) {
|
||||
public IndirectInstancer(StructType<P> type) {
|
||||
super(type);
|
||||
this.objectStride = type.getLayout()
|
||||
.getStride();
|
||||
writer = type.getWriter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDirty() {
|
||||
anyToUpdate = true;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return !anyToUpdate && !anyToRemove && instanceCount == 0;
|
||||
return changed.isEmpty() && deleted.isEmpty() && instanceCount == 0;
|
||||
}
|
||||
|
||||
void update() {
|
||||
if (anyToRemove) {
|
||||
if (!deleted.isEmpty()) {
|
||||
removeDeletedInstances();
|
||||
}
|
||||
|
||||
instanceCount = data.size();
|
||||
|
||||
anyToRemove = false;
|
||||
}
|
||||
|
||||
public void writeSparse(long objectPtr, long batchIDPtr, int batchID) {
|
||||
for (int i = 0, size = data.size(); i < size; i++) {
|
||||
final var element = data.get(i);
|
||||
if (element.checkDirtyAndClear()) {
|
||||
writer.write(objectPtr + i * objectStride, element);
|
||||
final int size = data.size();
|
||||
|
||||
MemoryUtil.memPutInt(batchIDPtr + i * IndirectBuffers.INT_SIZE, batchID);
|
||||
}
|
||||
for (int i = changed.nextSetBit(0); i >= 0 && i < size; i = changed.nextSetBit(i + 1)) {
|
||||
writer.write(objectPtr + i * objectStride, data.get(i));
|
||||
|
||||
MemoryUtil.memPutInt(batchIDPtr + i * IndirectBuffers.INT_SIZE, batchID);
|
||||
}
|
||||
changed.clear();
|
||||
}
|
||||
|
||||
public void writeFull(long objectPtr, long batchIDPtr, int batchID) {
|
||||
|
@ -62,10 +53,6 @@ public class IndirectInstancer<D extends InstancedPart> extends AbstractInstance
|
|||
MemoryUtil.memPutInt(batchIDPtr, batchID);
|
||||
batchIDPtr += IndirectBuffers.INT_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
// noop
|
||||
changed.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.layout.BufferLayout;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.struct.StructWriter;
|
||||
|
@ -15,25 +15,18 @@ import com.jozufozu.flywheel.gl.buffer.GlBufferType;
|
|||
import com.jozufozu.flywheel.gl.buffer.GlBufferUsage;
|
||||
import com.jozufozu.flywheel.gl.buffer.MappedBuffer;
|
||||
|
||||
public class GPUInstancer<D extends InstancedPart> extends AbstractInstancer<D> {
|
||||
public class GPUInstancer<P extends InstancePart> extends AbstractInstancer<P> {
|
||||
|
||||
final BufferLayout instanceFormat;
|
||||
final StructType<D> structType;
|
||||
final Set<GlVertexArray> boundTo = new HashSet<>();
|
||||
GlBuffer vbo;
|
||||
int glInstanceCount = 0;
|
||||
|
||||
boolean anyToUpdate;
|
||||
|
||||
public GPUInstancer(StructType<D> type) {
|
||||
public GPUInstancer(StructType<P> type) {
|
||||
super(type);
|
||||
this.instanceFormat = type.getLayout();
|
||||
this.structType = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDirty() {
|
||||
anyToUpdate = true;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
|
@ -46,11 +39,11 @@ public class GPUInstancer<D extends InstancedPart> extends AbstractInstancer<D>
|
|||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return !anyToUpdate && !anyToRemove && glInstanceCount == 0;
|
||||
return deleted.isEmpty() && changed.isEmpty() && glInstanceCount == 0;
|
||||
}
|
||||
|
||||
void update() {
|
||||
if (anyToRemove) {
|
||||
if (!deleted.isEmpty()) {
|
||||
removeDeletedInstances();
|
||||
}
|
||||
|
||||
|
@ -59,13 +52,11 @@ public class GPUInstancer<D extends InstancedPart> extends AbstractInstancer<D>
|
|||
boundTo.clear();
|
||||
}
|
||||
|
||||
if (anyToUpdate) {
|
||||
if (!changed.isEmpty()) {
|
||||
clearAndUpdateBuffer();
|
||||
}
|
||||
|
||||
glInstanceCount = data.size();
|
||||
|
||||
anyToRemove = anyToUpdate = false;
|
||||
}
|
||||
|
||||
private void clearAndUpdateBuffer() {
|
||||
|
@ -78,15 +69,14 @@ public class GPUInstancer<D extends InstancedPart> extends AbstractInstancer<D>
|
|||
|
||||
if (size > 0) {
|
||||
final long ptr = buf.getPtr();
|
||||
final long stride = structType.getLayout().getStride();
|
||||
final StructWriter<D> writer = structType.getWriter();
|
||||
final long stride = type.getLayout()
|
||||
.getStride();
|
||||
final StructWriter<P> writer = type.getWriter();
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
final D element = data.get(i);
|
||||
if (element.checkDirtyAndClear()) {
|
||||
writer.write(ptr + i * stride, element);
|
||||
}
|
||||
for (int i = changed.nextSetBit(0); i >= 0 && i < size; i = changed.nextSetBit(i + 1)) {
|
||||
writer.write(ptr + i * stride, data.get(i));
|
||||
}
|
||||
changed.clear();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Flywheel.LOGGER.error("Error updating GPUInstancer:", e);
|
||||
|
@ -104,7 +94,6 @@ public class GPUInstancer<D extends InstancedPart> extends AbstractInstancer<D>
|
|||
return vbo.ensureCapacity(requiredSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
vbo.delete();
|
||||
vbo = null;
|
||||
|
|
|
@ -14,7 +14,7 @@ import com.google.common.collect.ArrayListMultimap;
|
|||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.instancer.Instancer;
|
||||
import com.jozufozu.flywheel.api.model.Mesh;
|
||||
import com.jozufozu.flywheel.api.model.Model;
|
||||
|
@ -35,9 +35,9 @@ public class InstancingDrawManager {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <D extends InstancedPart> Instancer<D> getInstancer(StructType<D> type, Model model, RenderStage stage) {
|
||||
InstancerKey<D> key = new InstancerKey<>(type, model, stage);
|
||||
GPUInstancer<D> instancer = (GPUInstancer<D>) instancers.get(key);
|
||||
public <P extends InstancePart> Instancer<P> getInstancer(StructType<P> type, Model model, RenderStage stage) {
|
||||
InstancerKey<P> key = new InstancerKey<>(type, model, stage);
|
||||
GPUInstancer<P> instancer = (GPUInstancer<P>) instancers.get(key);
|
||||
if (instancer == null) {
|
||||
instancer = new GPUInstancer<>(type);
|
||||
instancers.put(key, instancer);
|
||||
|
|
|
@ -8,7 +8,7 @@ import com.jozufozu.flywheel.api.backend.Engine;
|
|||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.event.RenderContext;
|
||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.instancer.Instancer;
|
||||
import com.jozufozu.flywheel.api.model.Model;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
|
@ -41,7 +41,7 @@ public class InstancingEngine implements Engine {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <D extends InstancedPart> Instancer<D> instancer(StructType<D> type, Model model, RenderStage stage) {
|
||||
public <P extends InstancePart> Instancer<P> instancer(StructType<P> type, Model model, RenderStage stage) {
|
||||
return drawManager.getInstancer(type, model, stage);
|
||||
}
|
||||
|
||||
|
|
|
@ -39,37 +39,6 @@ public class BlockEntityInstanceManager extends InstanceManager<BlockEntity> {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canCreateInstance(BlockEntity blockEntity) {
|
||||
if (blockEntity.isRemoved()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!InstancingControllerHelper.canInstance(blockEntity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Level level = blockEntity.getLevel();
|
||||
|
||||
if (level == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (level.isEmptyBlock(blockEntity.getBlockPos())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (BackendUtil.isFlywheelLevel(level)) {
|
||||
BlockPos pos = blockEntity.getBlockPos();
|
||||
|
||||
BlockGetter existingChunk = level.getChunkForCollisions(pos.getX() >> 4, pos.getZ() >> 4);
|
||||
|
||||
return existingChunk != null;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class BlockEntityStorage extends One2OneStorage<BlockEntity> {
|
||||
private final Long2ObjectMap<BlockEntityInstance<?>> posLookup = new Long2ObjectOpenHashMap<>();
|
||||
|
||||
|
@ -77,6 +46,37 @@ public class BlockEntityInstanceManager extends InstanceManager<BlockEntity> {
|
|||
super(engine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean willAccept(BlockEntity blockEntity) {
|
||||
if (blockEntity.isRemoved()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!InstancingControllerHelper.canInstance(blockEntity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Level level = blockEntity.getLevel();
|
||||
|
||||
if (level == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (level.isEmptyBlock(blockEntity.getBlockPos())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (BackendUtil.isFlywheelLevel(level)) {
|
||||
BlockPos pos = blockEntity.getBlockPos();
|
||||
|
||||
BlockGetter existingChunk = level.getChunkForCollisions(pos.getX() >> 4, pos.getZ() >> 4);
|
||||
|
||||
return existingChunk != null;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected Instance createRaw(BlockEntity obj) {
|
||||
|
|
|
@ -21,11 +21,6 @@ public class EffectInstanceManager extends InstanceManager<Effect> {
|
|||
return storage;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canCreateInstance(Effect obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class EffectStorage extends One2ManyStorage<Effect> {
|
||||
public EffectStorage(Engine engine) {
|
||||
super(engine);
|
||||
|
@ -35,5 +30,10 @@ public class EffectInstanceManager extends InstanceManager<Effect> {
|
|||
protected Collection<? extends Instance> createRaw(Effect obj) {
|
||||
return obj.createInstances(new InstanceContext(engine, engine.renderOrigin()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean willAccept(Effect obj) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,21 +25,6 @@ public class EntityInstanceManager extends InstanceManager<Entity> {
|
|||
return storage;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canCreateInstance(Entity entity) {
|
||||
if (!entity.isAlive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!InstancingControllerHelper.canInstance(entity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Level level = entity.level;
|
||||
|
||||
return BackendUtil.isFlywheelLevel(level);
|
||||
}
|
||||
|
||||
private static class EntityStorage extends One2OneStorage<Entity> {
|
||||
public EntityStorage(Engine engine) {
|
||||
super(engine);
|
||||
|
@ -55,5 +40,20 @@ public class EntityInstanceManager extends InstanceManager<Entity> {
|
|||
|
||||
return controller.createInstance(new InstanceContext(engine, engine.renderOrigin()), obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean willAccept(Entity entity) {
|
||||
if (!entity.isAlive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!InstancingControllerHelper.canInstance(entity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Level level = entity.level;
|
||||
|
||||
return BackendUtil.isFlywheelLevel(level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,17 +31,6 @@ public abstract class InstanceManager<T> {
|
|||
|
||||
protected abstract Storage<T> getStorage();
|
||||
|
||||
/**
|
||||
* Is the given object currently capable of being instanced?
|
||||
*
|
||||
* <p>
|
||||
* This won't be the case for block entities or entities that are outside of loaded chunks.
|
||||
* </p>
|
||||
*
|
||||
* @return true if the object is currently capable of being instanced.
|
||||
*/
|
||||
protected abstract boolean canCreateInstance(T obj);
|
||||
|
||||
protected DistanceUpdateLimiter createUpdateLimiter() {
|
||||
if (FlwConfig.get().limitUpdates()) {
|
||||
return new BandedPrimeLimiter();
|
||||
|
@ -60,7 +49,7 @@ public abstract class InstanceManager<T> {
|
|||
}
|
||||
|
||||
public void add(T obj) {
|
||||
if (!canCreateInstance(obj)) {
|
||||
if (!getStorage().willAccept(obj)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -68,7 +57,7 @@ public abstract class InstanceManager<T> {
|
|||
}
|
||||
|
||||
public void queueAdd(T obj) {
|
||||
if (!canCreateInstance(obj)) {
|
||||
if (!getStorage().willAccept(obj)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -89,7 +78,7 @@ public abstract class InstanceManager<T> {
|
|||
* @param obj the object to update.
|
||||
*/
|
||||
public void update(T obj) {
|
||||
if (!canCreateInstance(obj)) {
|
||||
if (!getStorage().willAccept(obj)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -97,7 +86,7 @@ public abstract class InstanceManager<T> {
|
|||
}
|
||||
|
||||
public void queueUpdate(T obj) {
|
||||
if (!canCreateInstance(obj)) {
|
||||
if (!getStorage().willAccept(obj)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,13 @@ public interface Storage<T> {
|
|||
|
||||
List<DynamicInstance> getDynamicInstances();
|
||||
|
||||
/**
|
||||
* Is the given object currently capable of being added?
|
||||
*
|
||||
* @return true if the object is currently capable of being instanced.
|
||||
*/
|
||||
boolean willAccept(T obj);
|
||||
|
||||
void add(T obj);
|
||||
|
||||
void remove(T obj);
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package com.jozufozu.flywheel.lib.struct;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.Handle;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
|
||||
public abstract class AbstractInstancePart implements InstancePart {
|
||||
|
||||
public final StructType<?> type;
|
||||
protected final Handle handle;
|
||||
|
||||
protected AbstractInstancePart(StructType<?> type, Handle handle) {
|
||||
this.type = type;
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructType<?> type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public final void setChanged() {
|
||||
handle.setChanged();
|
||||
}
|
||||
|
||||
public final void delete() {
|
||||
handle.setDeleted();
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
package com.jozufozu.flywheel.lib.struct;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.Handle;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
|
||||
public abstract class ColoredLitPart extends InstancedPart implements FlatLit<ColoredLitPart> {
|
||||
public abstract class ColoredLitPart extends AbstractInstancePart implements FlatLit<ColoredLitPart> {
|
||||
|
||||
public byte blockLight;
|
||||
public byte skyLight;
|
||||
|
@ -15,21 +15,21 @@ public abstract class ColoredLitPart extends InstancedPart implements FlatLit<Co
|
|||
public byte b = (byte) 0xFF;
|
||||
public byte a = (byte) 0xFF;
|
||||
|
||||
public ColoredLitPart(StructType<?> type) {
|
||||
super(type);
|
||||
public ColoredLitPart(StructType<?> type, Handle handle) {
|
||||
super(type, handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColoredLitPart setBlockLight(int blockLight) {
|
||||
this.blockLight = (byte) blockLight;
|
||||
markDirty();
|
||||
setChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColoredLitPart setSkyLight(int skyLight) {
|
||||
this.skyLight = (byte) skyLight;
|
||||
markDirty();
|
||||
setChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ public abstract class ColoredLitPart extends InstancedPart implements FlatLit<Co
|
|||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
markDirty();
|
||||
setChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ public abstract class ColoredLitPart extends InstancedPart implements FlatLit<Co
|
|||
this.g = g;
|
||||
this.b = b;
|
||||
this.a = a;
|
||||
markDirty();
|
||||
setChanged();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,40 +1,39 @@
|
|||
package com.jozufozu.flywheel.lib.struct;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
|
||||
/**
|
||||
* An interface that implementors of {@link InstancedPart} should also implement
|
||||
* An interface that implementors of {@link InstancePart} should also implement
|
||||
* if they wish to make use of Flywheel's provided light update methods.
|
||||
* <p>
|
||||
* This only covers flat lighting, smooth lighting is still TODO.
|
||||
*
|
||||
* @param <D> The name of the class that implements this interface.
|
||||
* @param <P> The name of the class that implements this interface.
|
||||
*/
|
||||
public interface FlatLit<D extends InstancedPart & FlatLit<D>> {
|
||||
public interface FlatLit<P extends InstancePart & FlatLit<P>> {
|
||||
/**
|
||||
* @param blockLight An integer in the range [0, 15] representing the
|
||||
* amount of block light this instance should receive.
|
||||
* @return {@code this}
|
||||
*/
|
||||
D setBlockLight(int blockLight);
|
||||
P setBlockLight(int blockLight);
|
||||
|
||||
/**
|
||||
* @param skyLight An integer in the range [0, 15] representing the
|
||||
* amount of sky light this instance should receive.
|
||||
* @return {@code this}
|
||||
*/
|
||||
D setSkyLight(int skyLight);
|
||||
P setSkyLight(int skyLight);
|
||||
|
||||
default D setLight(int blockLight, int skyLight) {
|
||||
return setBlockLight(blockLight)
|
||||
.setSkyLight(skyLight);
|
||||
default P setLight(int blockLight, int skyLight) {
|
||||
return setBlockLight(blockLight).setSkyLight(skyLight);
|
||||
}
|
||||
|
||||
default D updateLight(BlockAndTintGetter level, BlockPos pos) {
|
||||
default P updateLight(BlockAndTintGetter level, BlockPos pos) {
|
||||
return setLight(level.getBrightness(LightLayer.BLOCK, pos), level.getBrightness(LightLayer.SKY, pos));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.jozufozu.flywheel.lib.struct;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.Handle;
|
||||
import com.mojang.math.Quaternion;
|
||||
import com.mojang.math.Vector3f;
|
||||
|
||||
|
@ -18,8 +19,8 @@ public class OrientedPart extends ColoredLitPart {
|
|||
public float qZ;
|
||||
public float qW = 1;
|
||||
|
||||
public OrientedPart() {
|
||||
super(StructTypes.ORIENTED);
|
||||
public OrientedPart(Handle handle) {
|
||||
super(StructTypes.ORIENTED, handle);
|
||||
}
|
||||
|
||||
public OrientedPart setPosition(BlockPos pos) {
|
||||
|
@ -34,7 +35,7 @@ public class OrientedPart extends ColoredLitPart {
|
|||
this.posX = x;
|
||||
this.posY = y;
|
||||
this.posZ = z;
|
||||
markDirty();
|
||||
setChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -42,7 +43,7 @@ public class OrientedPart extends ColoredLitPart {
|
|||
this.posX += x;
|
||||
this.posY += y;
|
||||
this.posZ += z;
|
||||
markDirty();
|
||||
setChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -58,7 +59,7 @@ public class OrientedPart extends ColoredLitPart {
|
|||
this.pivotX = x;
|
||||
this.pivotY = y;
|
||||
this.pivotZ = z;
|
||||
markDirty();
|
||||
setChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -71,7 +72,7 @@ public class OrientedPart extends ColoredLitPart {
|
|||
this.qY = y;
|
||||
this.qZ = z;
|
||||
this.qW = w;
|
||||
markDirty();
|
||||
setChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -80,13 +81,13 @@ public class OrientedPart extends ColoredLitPart {
|
|||
this.qY = 0;
|
||||
this.qZ = 0;
|
||||
this.qW = 1;
|
||||
markDirty();
|
||||
setChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrientedPart copy() {
|
||||
var out = new OrientedPart();
|
||||
public OrientedPart copy(Handle handle) {
|
||||
var out = new OrientedPart(handle);
|
||||
out.posX = this.posX;
|
||||
out.posY = this.posY;
|
||||
out.posZ = this.posZ;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.jozufozu.flywheel.lib.struct;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.Handle;
|
||||
import com.jozufozu.flywheel.api.layout.BufferLayout;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.struct.StructWriter;
|
||||
|
@ -24,8 +25,8 @@ public class OrientedType implements StructType<OrientedPart> {
|
|||
.build();
|
||||
|
||||
@Override
|
||||
public OrientedPart create() {
|
||||
return new OrientedPart();
|
||||
public OrientedPart create(Handle handle) {
|
||||
return new OrientedPart(handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.jozufozu.flywheel.lib.struct;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.Handle;
|
||||
import com.jozufozu.flywheel.lib.transform.Transform;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Matrix3f;
|
||||
|
@ -15,15 +16,17 @@ public class TransformedPart extends ColoredLitPart implements Transform<Transfo
|
|||
public final Matrix4f model = new Matrix4f();
|
||||
public final Matrix3f normal = new Matrix3f();
|
||||
|
||||
public TransformedPart() {
|
||||
super(StructTypes.TRANSFORMED);
|
||||
public TransformedPart(Handle handle) {
|
||||
super(StructTypes.TRANSFORMED, handle);
|
||||
}
|
||||
|
||||
public TransformedPart setTransform(PoseStack stack) {
|
||||
markDirty();
|
||||
setChanged();
|
||||
|
||||
this.model.load(stack.last().pose());
|
||||
this.normal.load(stack.last().normal());
|
||||
this.model.load(stack.last()
|
||||
.pose());
|
||||
this.normal.load(stack.last()
|
||||
.normal());
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -35,7 +38,7 @@ public class TransformedPart extends ColoredLitPart implements Transform<Transfo
|
|||
* </p>
|
||||
*/
|
||||
public TransformedPart setEmptyTransform() {
|
||||
markDirty();
|
||||
setChanged();
|
||||
|
||||
this.model.load(EMPTY_MATRIX_4f);
|
||||
this.normal.load(EMPTY_MATRIX_3f);
|
||||
|
@ -43,7 +46,7 @@ public class TransformedPart extends ColoredLitPart implements Transform<Transfo
|
|||
}
|
||||
|
||||
public TransformedPart loadIdentity() {
|
||||
markDirty();
|
||||
setChanged();
|
||||
|
||||
this.model.setIdentity();
|
||||
this.normal.setIdentity();
|
||||
|
@ -52,7 +55,7 @@ public class TransformedPart extends ColoredLitPart implements Transform<Transfo
|
|||
|
||||
@Override
|
||||
public TransformedPart multiply(Quaternion quaternion) {
|
||||
markDirty();
|
||||
setChanged();
|
||||
|
||||
model.multiply(quaternion);
|
||||
normal.mul(quaternion);
|
||||
|
@ -61,7 +64,7 @@ public class TransformedPart extends ColoredLitPart implements Transform<Transfo
|
|||
|
||||
@Override
|
||||
public TransformedPart scale(float pX, float pY, float pZ) {
|
||||
markDirty();
|
||||
setChanged();
|
||||
|
||||
model.multiply(Matrix4f.createScaleMatrix(pX, pY, pZ));
|
||||
if (pX == pY && pY == pZ) {
|
||||
|
@ -83,7 +86,7 @@ public class TransformedPart extends ColoredLitPart implements Transform<Transfo
|
|||
|
||||
@Override
|
||||
public TransformedPart translate(double x, double y, double z) {
|
||||
markDirty();
|
||||
setChanged();
|
||||
|
||||
model.multiplyWithTranslation((float) x, (float) y, (float) z);
|
||||
return this;
|
||||
|
@ -102,8 +105,8 @@ public class TransformedPart extends ColoredLitPart implements Transform<Transfo
|
|||
}
|
||||
|
||||
@Override
|
||||
public TransformedPart copy() {
|
||||
var out = new TransformedPart();
|
||||
public TransformedPart copy(Handle handle) {
|
||||
var out = new TransformedPart(handle);
|
||||
out.model.load(this.model);
|
||||
out.normal.load(this.normal);
|
||||
out.r = this.r;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.jozufozu.flywheel.lib.struct;
|
||||
|
||||
import com.jozufozu.flywheel.api.instancer.Handle;
|
||||
import com.jozufozu.flywheel.api.layout.BufferLayout;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.struct.StructWriter;
|
||||
|
@ -20,8 +21,8 @@ public class TransformedType implements StructType<TransformedPart> {
|
|||
.build();
|
||||
|
||||
@Override
|
||||
public TransformedPart create() {
|
||||
return new TransformedPart();
|
||||
public TransformedPart create(Handle handle) {
|
||||
return new TransformedPart(handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,7 +7,7 @@ import org.jetbrains.annotations.NotNull;
|
|||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instance.DynamicInstance;
|
||||
import com.jozufozu.flywheel.api.instance.controller.InstanceContext;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.lib.instance.AbstractBlockEntityInstance;
|
||||
import com.jozufozu.flywheel.lib.material.Materials;
|
||||
import com.jozufozu.flywheel.lib.model.SimpleLazyModel;
|
||||
|
@ -68,7 +68,7 @@ public class BellInstance extends AbstractBlockEntityInstance<BellBlockEntity> i
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<InstancedPart> getCrumblingParts() {
|
||||
public List<InstancePart> getCrumblingParts() {
|
||||
return List.of(bell);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import java.util.function.BiFunction;
|
|||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instance.DynamicInstance;
|
||||
import com.jozufozu.flywheel.api.instance.controller.InstanceContext;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.lib.instance.AbstractBlockEntityInstance;
|
||||
import com.jozufozu.flywheel.lib.material.Materials;
|
||||
import com.jozufozu.flywheel.lib.model.SimpleLazyModel;
|
||||
|
@ -111,7 +111,7 @@ public class ChestInstance<T extends BlockEntity & LidBlockEntity> extends Abstr
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<InstancedPart> getCrumblingParts() {
|
||||
public List<InstancePart> getCrumblingParts() {
|
||||
return List.of(body, lid);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import java.util.function.Function;
|
|||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instance.DynamicInstance;
|
||||
import com.jozufozu.flywheel.api.instance.controller.InstanceContext;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancePart;
|
||||
import com.jozufozu.flywheel.lib.instance.AbstractBlockEntityInstance;
|
||||
import com.jozufozu.flywheel.lib.material.Materials;
|
||||
import com.jozufozu.flywheel.lib.model.SimpleLazyModel;
|
||||
|
@ -95,7 +95,7 @@ public class ShulkerBoxInstance extends AbstractBlockEntityInstance<ShulkerBoxBl
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<InstancedPart> getCrumblingParts() {
|
||||
public List<InstancePart> getCrumblingParts() {
|
||||
return List.of(base, lid);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue