mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-07 02:34:58 +01:00
A little of everything
- Rename InstanceData -> InstancedPart, and subclasses - Burger Fences - Fix GlStateTracker nuking vao element buffer bindings - GlVertexArray tracks element buffer bindings - Use vertexAttribPointer offset instead of ..BaseVertex - Setup code for better crumbling rendering - Move some logic into CoreShaderInfoMap - Simplify VertexWriter/VertexList - Prefer IEventBus#addListener to @SubscribeEvent - Stop using persistent buffers... for now
This commit is contained in:
parent
d22f715f79
commit
08fff1c125
63 changed files with 861 additions and 495 deletions
|
@ -5,6 +5,9 @@ import org.slf4j.Logger;
|
|||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.OptifineHandler;
|
||||
import com.jozufozu.flywheel.backend.RenderWork;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
import com.jozufozu.flywheel.backend.model.MeshPool;
|
||||
import com.jozufozu.flywheel.config.BackendTypeArgument;
|
||||
import com.jozufozu.flywheel.config.FlwCommands;
|
||||
import com.jozufozu.flywheel.config.FlwConfig;
|
||||
|
@ -12,12 +15,16 @@ import com.jozufozu.flywheel.core.Contexts;
|
|||
import com.jozufozu.flywheel.core.GameStateRegistry;
|
||||
import com.jozufozu.flywheel.core.Models;
|
||||
import com.jozufozu.flywheel.core.PartialModel;
|
||||
import com.jozufozu.flywheel.core.QuadConverter;
|
||||
import com.jozufozu.flywheel.core.StitchedSprite;
|
||||
import com.jozufozu.flywheel.core.compile.ProgramCompiler;
|
||||
import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer;
|
||||
import com.jozufozu.flywheel.core.material.MaterialShaders;
|
||||
import com.jozufozu.flywheel.core.shader.NormalDebugStateProvider;
|
||||
import com.jozufozu.flywheel.core.structs.InstanceShaders;
|
||||
import com.jozufozu.flywheel.core.vertex.LayoutShaders;
|
||||
import com.jozufozu.flywheel.event.EntityWorldHandler;
|
||||
import com.jozufozu.flywheel.event.ForgeEvents;
|
||||
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
||||
import com.jozufozu.flywheel.mixin.PausedPartialTickAccessor;
|
||||
import com.jozufozu.flywheel.vanilla.VanillaInstances;
|
||||
|
@ -28,6 +35,7 @@ import net.minecraft.commands.synchronization.EmptyArgumentSerializer;
|
|||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.eventbus.api.EventPriority;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.fml.CrashReportCallables;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
|
@ -75,8 +83,25 @@ public class Flywheel {
|
|||
Backend.init();
|
||||
|
||||
forgeEventBus.addListener(FlwCommands::registerClientCommands);
|
||||
|
||||
forgeEventBus.addListener(EventPriority.HIGHEST, QuadConverter::onRendererReload);
|
||||
forgeEventBus.<ReloadRenderersEvent>addListener(ProgramCompiler::invalidateAll);
|
||||
forgeEventBus.addListener(Models::onReload);
|
||||
forgeEventBus.addListener(MeshPool::reset);
|
||||
forgeEventBus.addListener(CrumblingRenderer::onReloadRenderers);
|
||||
|
||||
forgeEventBus.addListener(InstancedRenderDispatcher::onReloadRenderers);
|
||||
forgeEventBus.addListener(InstancedRenderDispatcher::onBeginFrame);
|
||||
forgeEventBus.addListener(InstancedRenderDispatcher::tick);
|
||||
|
||||
forgeEventBus.addListener(EntityWorldHandler::onEntityJoinWorld);
|
||||
forgeEventBus.addListener(EntityWorldHandler::onEntityLeaveWorld);
|
||||
|
||||
forgeEventBus.addListener(ForgeEvents::addToDebugScreen);
|
||||
forgeEventBus.addListener(ForgeEvents::unloadWorld);
|
||||
forgeEventBus.addListener(ForgeEvents::tickLight);
|
||||
|
||||
forgeEventBus.addListener(EventPriority.LOWEST, RenderWork::onRenderWorldLast);
|
||||
|
||||
modEventBus.addListener(PartialModel::onModelRegistry);
|
||||
modEventBus.addListener(PartialModel::onModelBake);
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
package com.jozufozu.flywheel.api;
|
||||
|
||||
public abstract class InstanceData {
|
||||
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();
|
||||
|
@ -34,8 +41,9 @@ public abstract class InstanceData {
|
|||
return owner;
|
||||
}
|
||||
|
||||
public InstanceData setOwner(Instancer<?> owner) {
|
||||
public void setOwner(Instancer<?> owner) {
|
||||
this.owner = owner;
|
||||
return this;
|
||||
}
|
||||
|
||||
public abstract InstancedPart copy();
|
||||
}
|
|
@ -18,7 +18,7 @@ package com.jozufozu.flywheel.api;
|
|||
*
|
||||
* @param <D> the data that represents a copy of the instanced model.
|
||||
*/
|
||||
public interface Instancer<D extends InstanceData> {
|
||||
public interface Instancer<D extends InstancedPart> {
|
||||
/**
|
||||
* @return a handle to a new copy of this model.
|
||||
*/
|
||||
|
|
|
@ -2,7 +2,7 @@ package com.jozufozu.flywheel.api;
|
|||
|
||||
import com.jozufozu.flywheel.core.model.ModelSupplier;
|
||||
|
||||
public interface InstancerFactory<D extends InstanceData> {
|
||||
public interface InstancerFactory<D extends InstancedPart> {
|
||||
|
||||
/**
|
||||
* Get an instancer for the given model. Calling this method twice with the same key will return the same instancer.
|
||||
|
|
|
@ -6,7 +6,7 @@ import net.minecraft.core.Vec3i;
|
|||
|
||||
public interface InstancerManager {
|
||||
|
||||
<D extends InstanceData> InstancerFactory<D> factory(StructType<D> type);
|
||||
<D extends InstancedPart> InstancerFactory<D> factory(StructType<D> type);
|
||||
|
||||
Vec3i getOriginCoordinate();
|
||||
|
||||
|
|
|
@ -11,5 +11,5 @@ public interface MaterialGroup {
|
|||
* @param <D> The type representing the per instance data.
|
||||
* @return A material you can use to render models.
|
||||
*/
|
||||
<D extends InstanceData> InstancerFactory<D> material(StructType<D> spec);
|
||||
<D extends InstancedPart> InstancerFactory<D> material(StructType<D> spec);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.jozufozu.flywheel.api.instance;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.Instancer;
|
||||
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
|
||||
|
||||
|
@ -19,7 +19,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 InstanceData} creation/acquisition is safe here.
|
||||
* {@link Instancer}/{@link InstancedPart} creation/acquisition is safe here.
|
||||
*/
|
||||
void beginFrame();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.jozufozu.flywheel.api.instance;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.Instancer;
|
||||
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
|
||||
|
||||
|
@ -27,7 +27,7 @@ public interface TickableInstance extends Instance {
|
|||
* <br>
|
||||
* <em>DISPATCHED IN PARALLEL</em>, don't attempt to mutate anything outside of this instance.
|
||||
* <br>
|
||||
* {@link Instancer}/{@link InstanceData} creation/acquisition is safe here.
|
||||
* {@link Instancer}/{@link InstancedPart} creation/acquisition is safe here.
|
||||
*/
|
||||
void tick();
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@ package com.jozufozu.flywheel.api.vertex;
|
|||
public interface VertexWriter {
|
||||
void writeVertex(VertexList list, int index);
|
||||
|
||||
void seekToVertex(int vertex);
|
||||
void seek(long offset);
|
||||
|
||||
VertexList intoReader();
|
||||
VertexList intoReader(int vertices);
|
||||
|
||||
default void writeVertexList(VertexList list) {
|
||||
for (int i = 0; i < list.getVertexCount(); i++) {
|
||||
|
|
|
@ -3,18 +3,12 @@ package com.jozufozu.flywheel.backend;
|
|||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.RenderLevelLastEvent;
|
||||
import net.minecraftforge.eventbus.api.EventPriority;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
@Mod.EventBusSubscriber(Dist.CLIENT)
|
||||
public class RenderWork {
|
||||
private static final Queue<Runnable> runs = new ConcurrentLinkedQueue<>();
|
||||
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.LOWEST)
|
||||
public static void onRenderWorldLast(RenderLevelLastEvent event) {
|
||||
while (!runs.isEmpty()) {
|
||||
runs.remove()
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
package com.jozufozu.flywheel.backend.gl;
|
||||
|
||||
import static org.lwjgl.opengl.GL32.GL_ALREADY_SIGNALED;
|
||||
import static org.lwjgl.opengl.GL32.GL_CONDITION_SATISFIED;
|
||||
import static org.lwjgl.opengl.GL32.GL_SIGNALED;
|
||||
import static org.lwjgl.opengl.GL32.GL_SYNC_FLUSH_COMMANDS_BIT;
|
||||
import static org.lwjgl.opengl.GL32.GL_SYNC_GPU_COMMANDS_COMPLETE;
|
||||
import static org.lwjgl.opengl.GL32.GL_UNSIGNALED;
|
||||
import static org.lwjgl.opengl.GL32.GL_SYNC_STATUS;
|
||||
import static org.lwjgl.opengl.GL32.GL_TIMEOUT_IGNORED;
|
||||
import static org.lwjgl.opengl.GL32.glClientWaitSync;
|
||||
import static org.lwjgl.opengl.GL32.glDeleteSync;
|
||||
import static org.lwjgl.opengl.GL32.glFenceSync;
|
||||
|
||||
import org.lwjgl.opengl.GL32;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
// https://github.com/CaffeineMC/sodium-fabric/blob/da17fc8d0cb1a4e82fe6956ac4f07a63d32eca5a/components/gfx-opengl/src/main/java/net/caffeinemc/gfx/opengl/sync/GlFence.java
|
||||
public class GlFence {
|
||||
|
||||
private long fence;
|
||||
|
@ -26,16 +31,38 @@ public class GlFence {
|
|||
}
|
||||
}
|
||||
|
||||
public void waitSync() {
|
||||
public boolean poll() {
|
||||
if (fence != 0) {
|
||||
int waitReturn = GL_UNSIGNALED;
|
||||
while (waitReturn != GL_ALREADY_SIGNALED && waitReturn != GL_CONDITION_SATISFIED) {
|
||||
waitReturn = glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, 1);
|
||||
poll0();
|
||||
}
|
||||
|
||||
glDeleteSync(fence);
|
||||
return fence == 0;
|
||||
}
|
||||
|
||||
private void poll0() {
|
||||
int result;
|
||||
try (var memoryStack = MemoryStack.stackPush()) {
|
||||
long checkPtr = memoryStack.ncalloc(Integer.BYTES, 0, Integer.BYTES);
|
||||
GL32.nglGetSynciv(fence, GL_SYNC_STATUS, 1, MemoryUtil.NULL, checkPtr);
|
||||
|
||||
result = MemoryUtil.memGetInt(checkPtr);
|
||||
}
|
||||
|
||||
if (result == GL_SIGNALED) {
|
||||
glDeleteSync(fence);
|
||||
fence = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void waitSync() {
|
||||
if (poll()) {
|
||||
return;
|
||||
}
|
||||
|
||||
glClientWaitSync(fence, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
|
||||
|
||||
glDeleteSync(fence);
|
||||
|
||||
fence = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,20 +42,20 @@ public class GlStateTracker {
|
|||
|
||||
public record State(int[] buffers, int vao, int program) implements AutoCloseable {
|
||||
public void restore() {
|
||||
GlBufferType[] values = GlBufferType.values();
|
||||
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (buffers[i] != GlStateTracker.buffers[i]) {
|
||||
GlStateManager._glBindBuffer(values[i].glEnum, buffers[i]);
|
||||
}
|
||||
if (program != GlStateTracker.program) {
|
||||
GlStateManager._glUseProgram(program);
|
||||
}
|
||||
|
||||
if (vao != GlStateTracker.vao) {
|
||||
GlStateManager._glBindVertexArray(vao);
|
||||
}
|
||||
|
||||
if (program != GlStateTracker.program) {
|
||||
GlStateManager._glUseProgram(program);
|
||||
GlBufferType[] values = GlBufferType.values();
|
||||
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (buffers[i] != GlStateTracker.buffers[i]) {
|
||||
GlStateManager._glBindBuffer(values[i].glEnum, buffers[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,13 +36,15 @@ public class GlVertexArray extends GlObject {
|
|||
/**
|
||||
* Each attribute's offset.
|
||||
*/
|
||||
private final int[] offsets = new int[MAX_ATTRIBS];
|
||||
private final long[] offsets = new long[MAX_ATTRIBS];
|
||||
|
||||
/**
|
||||
* Each attribute's stride.
|
||||
*/
|
||||
private final int[] strides = new int[MAX_ATTRIBS];
|
||||
|
||||
private int elementBufferBinding = 0;
|
||||
|
||||
|
||||
public GlVertexArray() {
|
||||
setHandle(GlStateManager._glGenVertexArrays());
|
||||
|
@ -62,15 +64,20 @@ public class GlVertexArray extends GlObject {
|
|||
GlStateManager._glBindVertexArray(0);
|
||||
}
|
||||
|
||||
public void bindAttributes(GlBuffer buffer, int startIndex, BufferLayout type) {
|
||||
/**
|
||||
* @param buffer The buffer where the data is stored.
|
||||
* @param startAttrib The first attribute to be used by the data.
|
||||
* @param type The format of the attributes.
|
||||
* @param offset The offset in bytes to the start of the data.
|
||||
*/
|
||||
public void bindAttributes(GlBuffer buffer, int startAttrib, BufferLayout type, long offset) {
|
||||
bind();
|
||||
|
||||
int targetBuffer = buffer.handle();
|
||||
|
||||
GlBufferType.ARRAY_BUFFER.bind(targetBuffer);
|
||||
|
||||
int i = startIndex;
|
||||
int offset = 0;
|
||||
int i = startAttrib;
|
||||
final int stride = type.getStride();
|
||||
|
||||
for (VertexAttribute attribute : type.getAttributes()) {
|
||||
|
@ -126,4 +133,13 @@ public class GlVertexArray extends GlObject {
|
|||
divisors[index] = divisor;
|
||||
}
|
||||
}
|
||||
|
||||
public void bindElementArray(GlBuffer ebo) {
|
||||
int handle = ebo.handle();
|
||||
if (elementBufferBinding != handle) {
|
||||
bind();
|
||||
GlBufferType.ELEMENT_ARRAY_BUFFER.bind(handle);
|
||||
elementBufferBinding = handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,13 +77,6 @@ public abstract class GlBuffer extends GlObject {
|
|||
*/
|
||||
public abstract boolean ensureCapacity(long size);
|
||||
|
||||
/**
|
||||
* Call this after all draw calls using this buffer are complete.
|
||||
*/
|
||||
public void doneForThisFrame() {
|
||||
|
||||
}
|
||||
|
||||
protected void deleteInternal(int handle) {
|
||||
GL20.glDeleteBuffers(handle);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import org.jetbrains.annotations.Nullable;
|
|||
import org.lwjgl.opengl.GL32;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlFence;
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlError;
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlException;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
||||
|
@ -19,19 +18,12 @@ public class PersistentGlBuffer extends GlBuffer {
|
|||
|
||||
@Nullable
|
||||
private MappedBuffer access;
|
||||
int flags;
|
||||
private final GlFence fence;
|
||||
private final int storageFlags;
|
||||
|
||||
public PersistentGlBuffer(GlBufferType type) {
|
||||
super(type);
|
||||
|
||||
flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
|
||||
fence = new GlFence();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doneForThisFrame() {
|
||||
fence.post();
|
||||
storageFlags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -47,7 +39,7 @@ public class PersistentGlBuffer extends GlBuffer {
|
|||
if (this.size == 0) {
|
||||
this.size = size;
|
||||
bind();
|
||||
GlCompat.getInstance().bufferStorage.bufferStorage(type, this.size, flags);
|
||||
GlCompat.getInstance().bufferStorage.bufferStorage(type, this.size, storageFlags);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -55,8 +47,6 @@ public class PersistentGlBuffer extends GlBuffer {
|
|||
var oldSize = this.size;
|
||||
this.size = size + growthMargin;
|
||||
|
||||
fence.clear();
|
||||
|
||||
realloc(this.size, oldSize);
|
||||
|
||||
access = null;
|
||||
|
@ -89,7 +79,7 @@ public class PersistentGlBuffer extends GlBuffer {
|
|||
|
||||
private void mapToClientMemory() {
|
||||
bind();
|
||||
ByteBuffer byteBuffer = GL32.glMapBufferRange(type.glEnum, 0, size, flags);
|
||||
ByteBuffer byteBuffer = GL32.glMapBufferRange(type.glEnum, 0, size, storageFlags);
|
||||
|
||||
if (byteBuffer == null) {
|
||||
throw new GlException(GlError.poll(), "Could not map buffer");
|
||||
|
@ -105,7 +95,7 @@ public class PersistentGlBuffer extends GlBuffer {
|
|||
GlBufferType.COPY_READ_BUFFER.bind(oldHandle);
|
||||
type.bind(newHandle);
|
||||
|
||||
GlCompat.getInstance().bufferStorage.bufferStorage(type, newSize, flags);
|
||||
GlCompat.getInstance().bufferStorage.bufferStorage(type, newSize, storageFlags);
|
||||
|
||||
GL32.glCopyBufferSubData(GlBufferType.COPY_READ_BUFFER.glEnum, type.glEnum, 0, 0, oldSize);
|
||||
|
||||
|
@ -122,8 +112,6 @@ public class PersistentGlBuffer extends GlBuffer {
|
|||
private MappedBuffer getWriteAccess() {
|
||||
if (access == null) {
|
||||
mapToClientMemory();
|
||||
} else {
|
||||
fence.waitSync(); // FIXME: Hangs too much, needs double/triple buffering
|
||||
}
|
||||
|
||||
return access;
|
||||
|
|
|
@ -2,20 +2,20 @@ package com.jozufozu.flywheel.backend.instancing;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.Instancer;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
|
||||
public abstract class AbstractInstancer<D extends InstanceData> implements Instancer<D> {
|
||||
public abstract class AbstractInstancer<D extends InstancedPart> implements Instancer<D> {
|
||||
|
||||
protected final Supplier<D> factory;
|
||||
protected final StructType<D> type;
|
||||
protected final ArrayList<D> data = new ArrayList<>();
|
||||
|
||||
protected boolean anyToRemove;
|
||||
|
||||
protected AbstractInstancer(Supplier<D> factory) {
|
||||
this.factory = factory;
|
||||
protected AbstractInstancer(StructType<D> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,7 +23,7 @@ public abstract class AbstractInstancer<D extends InstanceData> implements Insta
|
|||
*/
|
||||
@Override
|
||||
public D createInstance() {
|
||||
return _add(factory.get());
|
||||
return _add(type.create());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -141,8 +141,7 @@ public class InstanceWorld {
|
|||
public void loadEntities(ClientLevel world) {
|
||||
// Block entities are loaded while chunks are baked.
|
||||
// Entities are loaded with the world, so when chunks are reloaded they need to be re-added.
|
||||
ClientLevelExtension.cast(world)
|
||||
.flywheel$getAllLoadedEntities()
|
||||
ClientLevelExtension.getAllLoadedEntities(world)
|
||||
.forEach(entityInstanceManager::add);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.jozufozu.flywheel.backend.instancing;
|
|||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.model.MeshPool;
|
||||
import com.jozufozu.flywheel.config.FlwCommands;
|
||||
import com.jozufozu.flywheel.config.FlwConfig;
|
||||
import com.jozufozu.flywheel.core.RenderContext;
|
||||
|
@ -22,7 +23,6 @@ import net.minecraftforge.event.TickEvent;
|
|||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
@Mod.EventBusSubscriber(Dist.CLIENT)
|
||||
public class InstancedRenderDispatcher {
|
||||
|
||||
private static final WorldAttached<InstanceWorld> instanceWorlds = new WorldAttached<>(InstanceWorld::create);
|
||||
|
@ -71,7 +71,6 @@ public class InstancedRenderDispatcher {
|
|||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void tick(TickEvent.ClientTickEvent event) {
|
||||
if (!Backend.isGameActive() || event.phase == TickEvent.Phase.START) {
|
||||
return;
|
||||
|
@ -86,7 +85,6 @@ public class InstancedRenderDispatcher {
|
|||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onBeginFrame(BeginFrameEvent event) {
|
||||
if (Backend.isGameActive() && Backend.isOn()) {
|
||||
instanceWorlds.get(event.getWorld())
|
||||
|
@ -108,7 +106,6 @@ public class InstancedRenderDispatcher {
|
|||
instanceWorlds.get(world).renderAllRemaining(context);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onReloadRenderers(ReloadRenderersEvent event) {
|
||||
ClientLevel world = event.getWorld();
|
||||
if (Backend.isOn() && world != null) {
|
||||
|
|
|
@ -3,7 +3,7 @@ package com.jozufozu.flywheel.backend.instancing.batching;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.MaterialGroup;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.instancing.BatchDrawingTracker;
|
||||
|
@ -16,7 +16,7 @@ public class BatchedMaterialGroup implements MaterialGroup {
|
|||
|
||||
protected final RenderType state;
|
||||
|
||||
private final Map<StructType<? extends InstanceData>, CPUInstancerFactory<?>> materials = new HashMap<>();
|
||||
private final Map<StructType<? extends InstancedPart>, CPUInstancerFactory<?>> materials = new HashMap<>();
|
||||
private int vertexCount;
|
||||
private int instanceCount;
|
||||
|
||||
|
@ -26,7 +26,7 @@ public class BatchedMaterialGroup implements MaterialGroup {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <D extends InstanceData> CPUInstancerFactory<D> material(StructType<D> type) {
|
||||
public <D extends InstancedPart> CPUInstancerFactory<D> material(StructType<D> type) {
|
||||
return (CPUInstancerFactory<D>) materials.computeIfAbsent(type, CPUInstancerFactory::new);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.instancing.BatchDrawingTracker;
|
||||
import com.jozufozu.flywheel.backend.instancing.Engine;
|
||||
|
@ -20,12 +20,12 @@ import net.minecraft.core.Vec3i;
|
|||
|
||||
public class BatchingEngine implements Engine {
|
||||
|
||||
private final Map<StructType<? extends InstanceData>, CPUInstancerFactory<?>> factories = new HashMap<>();
|
||||
private final Map<StructType<? extends InstancedPart>, CPUInstancerFactory<?>> factories = new HashMap<>();
|
||||
private final BatchDrawingTracker batchTracker = new BatchDrawingTracker();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <D extends InstanceData> CPUInstancerFactory<D> factory(StructType<D> type) {
|
||||
public <D extends InstancedPart> CPUInstancerFactory<D> factory(StructType<D> type) {
|
||||
return (CPUInstancerFactory<D>) factories.computeIfAbsent(type, CPUInstancerFactory::new);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.batching;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
|
||||
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||
|
@ -8,14 +8,14 @@ import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
|
|||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
public class CPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
||||
public class CPUInstancer<D extends InstancedPart> extends AbstractInstancer<D> {
|
||||
|
||||
// private final Batched<D> batchingType;
|
||||
//
|
||||
// final ModelTransformer sbb;
|
||||
|
||||
public CPUInstancer(StructType<D> type) {
|
||||
super(type::create);
|
||||
super(type);
|
||||
// batchingType = type;
|
||||
//
|
||||
// sbb = new ModelTransformer(modelData.get());
|
||||
|
|
|
@ -3,7 +3,7 @@ package com.jozufozu.flywheel.backend.instancing.batching;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.Instancer;
|
||||
import com.jozufozu.flywheel.api.InstancerFactory;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
|
@ -11,7 +11,7 @@ import com.jozufozu.flywheel.core.model.ModelSupplier;
|
|||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
public class CPUInstancerFactory<D extends InstanceData> implements InstancerFactory<D> {
|
||||
public class CPUInstancerFactory<D extends InstancedPart> implements InstancerFactory<D> {
|
||||
|
||||
protected final Map<ModelSupplier, CPUInstancer<D>> models;
|
||||
private final StructType<D> type;
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.blockentity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.InstancerFactory;
|
||||
import com.jozufozu.flywheel.api.InstancerManager;
|
||||
import com.jozufozu.flywheel.api.instance.DynamicInstance;
|
||||
import com.jozufozu.flywheel.api.instance.TickableInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
|
||||
import com.jozufozu.flywheel.core.structs.StructTypes;
|
||||
import com.jozufozu.flywheel.core.structs.model.ModelData;
|
||||
import com.jozufozu.flywheel.core.structs.oriented.OrientedData;
|
||||
import com.jozufozu.flywheel.core.structs.model.TransformedPart;
|
||||
import com.jozufozu.flywheel.core.structs.oriented.OrientedPart;
|
||||
import com.jozufozu.flywheel.util.box.GridAlignedBB;
|
||||
import com.jozufozu.flywheel.util.box.ImmutableBox;
|
||||
|
||||
|
@ -47,6 +51,16 @@ public abstract class BlockEntityInstance<T extends BlockEntity> extends Abstrac
|
|||
this.instancePos = pos.subtract(instancerManager.getOriginCoordinate());
|
||||
}
|
||||
|
||||
public List<InstancedPart> getCrumblingParts() {
|
||||
var out = new ArrayList<InstancedPart>();
|
||||
addCrumblingParts(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
public void addCrumblingParts(List<InstancedPart> data) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Just before {@link #update()} would be called, {@code shouldReset()} is checked.
|
||||
* If this function returns {@code true}, then this instance will be {@link #remove removed},
|
||||
|
@ -76,11 +90,11 @@ public abstract class BlockEntityInstance<T extends BlockEntity> extends Abstrac
|
|||
return pos;
|
||||
}
|
||||
|
||||
protected InstancerFactory<ModelData> getTransformFactory() {
|
||||
return instancerManager.factory(StructTypes.MODEL);
|
||||
protected InstancerFactory<TransformedPart> getTransformFactory() {
|
||||
return instancerManager.factory(StructTypes.TRANSFORMED);
|
||||
}
|
||||
|
||||
protected InstancerFactory<OrientedData> getOrientedFactory() {
|
||||
protected InstancerFactory<OrientedPart> getOrientedFactory() {
|
||||
return instancerManager.factory(StructTypes.ORIENTED);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.blockentity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstancerManager;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
@ -13,10 +17,19 @@ import net.minecraft.world.level.block.entity.BlockEntity;
|
|||
|
||||
public class BlockEntityInstanceManager extends InstanceManager<BlockEntity> {
|
||||
|
||||
private final Long2ObjectMap<BlockEntityInstance<?>> posLookup = new Long2ObjectOpenHashMap<>();
|
||||
|
||||
public BlockEntityInstanceManager(InstancerManager instancerManager) {
|
||||
super(instancerManager);
|
||||
}
|
||||
|
||||
public void getCrumblingInstances(long pos, List<BlockEntityInstance<?>> data) {
|
||||
BlockEntityInstance<?> instance = posLookup.get(pos);
|
||||
if (instance != null) {
|
||||
data.add(instance);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canInstance(BlockEntity obj) {
|
||||
return obj != null && InstancedRenderRegistry.canInstance(obj.getType());
|
||||
|
@ -24,7 +37,20 @@ public class BlockEntityInstanceManager extends InstanceManager<BlockEntity> {
|
|||
|
||||
@Override
|
||||
protected AbstractInstance createRaw(BlockEntity obj) {
|
||||
return InstancedRenderRegistry.createInstance(instancerManager, obj);
|
||||
var instance = InstancedRenderRegistry.createInstance(instancerManager, obj);
|
||||
|
||||
if (instance != null) {
|
||||
BlockPos blockPos = obj.getBlockPos();
|
||||
posLookup.put(blockPos.asLong(), instance);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeInternal(BlockEntity obj, AbstractInstance instance) {
|
||||
super.removeInternal(obj, instance);
|
||||
posLookup.remove(obj.getBlockPos().asLong());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -4,20 +4,22 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.struct.StructWriter;
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
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.gl.buffer.MappedGlBuffer;
|
||||
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
|
||||
import com.jozufozu.flywheel.core.layout.BufferLayout;
|
||||
|
||||
public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
||||
public class GPUInstancer<D extends InstancedPart> extends AbstractInstancer<D> {
|
||||
|
||||
final BufferLayout instanceFormat;
|
||||
final StructType<D> instancedType;
|
||||
public final BufferLayout instanceFormat;
|
||||
public final StructType<D> structType;
|
||||
public final InstancedModel<D> parent;
|
||||
|
||||
GlBuffer vbo;
|
||||
int attributeBaseIndex;
|
||||
|
@ -25,10 +27,11 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
|
||||
boolean anyToUpdate;
|
||||
|
||||
public GPUInstancer(StructType<D> type) {
|
||||
super(type::create);
|
||||
public GPUInstancer(InstancedModel<D> parent, StructType<D> type) {
|
||||
super(type);
|
||||
this.parent = parent;
|
||||
this.instanceFormat = type.getLayout();
|
||||
instancedType = type;
|
||||
this.structType = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -39,7 +42,7 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
public void init() {
|
||||
if (vbo != null) return;
|
||||
|
||||
vbo = GlBuffer.requestPersistent(GlBufferType.ARRAY_BUFFER);
|
||||
vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER);
|
||||
vbo.setGrowthMargin(instanceFormat.getStride() * 16);
|
||||
}
|
||||
|
||||
|
@ -82,7 +85,7 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
|
||||
if (size > 0) {
|
||||
|
||||
final StructWriter<D> writer = instancedType.getWriter(buf.unwrap());
|
||||
final StructWriter<D> writer = structType.getWriter(buf.unwrap());
|
||||
|
||||
boolean sequential = true;
|
||||
for (int i = 0; i < size; i++) {
|
||||
|
@ -115,7 +118,7 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
}
|
||||
|
||||
private void bindInstanceAttributes(GlVertexArray vao) {
|
||||
vao.bindAttributes(this.vbo, this.attributeBaseIndex, this.instanceFormat);
|
||||
vao.bindAttributes(this.vbo, this.attributeBaseIndex, this.instanceFormat, 0L);
|
||||
|
||||
for (int i = 0; i < this.instanceFormat.getAttributeCount(); i++) {
|
||||
vao.setAttributeDivisor(this.attributeBaseIndex + i, 1);
|
||||
|
|
|
@ -4,16 +4,16 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.Instancer;
|
||||
import com.jozufozu.flywheel.api.InstancerFactory;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.model.MeshPool;
|
||||
import com.jozufozu.flywheel.core.model.ModelSupplier;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
@ -22,16 +22,14 @@ import net.minecraft.client.renderer.RenderType;
|
|||
* A collection of Instancers that all have the same format.
|
||||
* @param <D>
|
||||
*/
|
||||
public class GPUInstancerFactory<D extends InstanceData> implements InstancerFactory<D> {
|
||||
public class GPUInstancerFactory<D extends InstancedPart> implements InstancerFactory<D> {
|
||||
|
||||
protected final Map<ModelSupplier, InstancedModel<D>> models = new HashMap<>();
|
||||
protected final StructType<D> type;
|
||||
|
||||
protected final List<InstancedModel<D>> uninitialized = new ArrayList<>();
|
||||
|
||||
// FIXME: these should not be public
|
||||
public final Multimap<RenderType, Material> materials = HashMultimap.create();
|
||||
public final Multimap<Material, Renderable> renderables = ArrayListMultimap.create();
|
||||
private final ListMultimap<RenderType, Renderable> renderLists = ArrayListMultimap.create();
|
||||
|
||||
public GPUInstancerFactory(StructType<D> type) {
|
||||
this.type = type;
|
||||
|
@ -39,7 +37,7 @@ public class GPUInstancerFactory<D extends InstanceData> implements InstancerFac
|
|||
|
||||
@Override
|
||||
public Instancer<D> model(ModelSupplier modelKey) {
|
||||
return models.computeIfAbsent(modelKey, this::createInstancer).instancer;
|
||||
return models.computeIfAbsent(modelKey, this::createInstancer).getInstancer();
|
||||
}
|
||||
|
||||
public int getInstanceCount() {
|
||||
|
@ -60,8 +58,7 @@ public class GPUInstancerFactory<D extends InstanceData> implements InstancerFac
|
|||
public void delete() {
|
||||
models.values().forEach(InstancedModel::delete);
|
||||
models.clear();
|
||||
materials.clear();
|
||||
renderables.clear();
|
||||
renderLists.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,21 +71,35 @@ public class GPUInstancerFactory<D extends InstanceData> implements InstancerFac
|
|||
.forEach(GPUInstancer::clear);
|
||||
}
|
||||
|
||||
public void init(MeshPool allocator) {
|
||||
public void init() {
|
||||
for (var instanced : uninitialized) {
|
||||
var map = instanced.init(allocator);
|
||||
instanced.init();
|
||||
|
||||
map.forEach((material, renderable) -> {
|
||||
materials.put(material.getRenderType(), material);
|
||||
renderables.get(material).add(renderable);
|
||||
});
|
||||
for (Renderable renderable : instanced.getLayers()) {
|
||||
renderLists.put(renderable.getMaterial()
|
||||
.getRenderType(), renderable);
|
||||
}
|
||||
}
|
||||
uninitialized.clear();
|
||||
}
|
||||
|
||||
private InstancedModel<D> createInstancer(ModelSupplier model) {
|
||||
var instancer = new InstancedModel<>(new GPUInstancer<>(type), model);
|
||||
var instancer = new InstancedModel<>(type, model);
|
||||
uninitialized.add(instancer);
|
||||
return instancer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all the RenderTypes that this InstancerFactory will render to the given set.
|
||||
* @param layersToProcess The set of RenderTypes that the InstancingEngine will process.
|
||||
*/
|
||||
public void gatherLayers(Set<RenderType> layersToProcess) {
|
||||
layersToProcess.addAll(renderLists.keySet());
|
||||
}
|
||||
|
||||
public List<Renderable> getRenderList(RenderType type) {
|
||||
var out = renderLists.get(type);
|
||||
out.removeIf(Renderable::shouldRemove);
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.backend.model.MeshPool;
|
||||
|
@ -12,28 +15,33 @@ import com.jozufozu.flywheel.core.model.Mesh;
|
|||
import com.jozufozu.flywheel.core.model.ModelSupplier;
|
||||
import com.jozufozu.flywheel.util.Pair;
|
||||
|
||||
public class InstancedModel<D extends InstanceData> {
|
||||
public class InstancedModel<D extends InstancedPart> {
|
||||
|
||||
final GPUInstancer<D> instancer;
|
||||
final ModelSupplier model;
|
||||
private Map<Material, Layer> layers;
|
||||
public final GPUInstancer<D> instancer;
|
||||
public final ModelSupplier model;
|
||||
private List<Layer> layers;
|
||||
|
||||
public InstancedModel(GPUInstancer<D> instancer, ModelSupplier model) {
|
||||
this.instancer = instancer;
|
||||
public InstancedModel(StructType<D> type, ModelSupplier model) {
|
||||
this.model = model;
|
||||
this.instancer = new GPUInstancer<>(this, type);
|
||||
}
|
||||
|
||||
public Map<Material, ? extends Renderable> init(MeshPool allocator) {
|
||||
public void init() {
|
||||
instancer.init();
|
||||
|
||||
buildLayers();
|
||||
}
|
||||
|
||||
public List<? extends Renderable> getLayers() {
|
||||
return layers;
|
||||
}
|
||||
|
||||
private void buildLayers() {
|
||||
layers = model.get()
|
||||
.entrySet()
|
||||
.stream()
|
||||
.map(entry -> Pair.of(entry.getKey(), new Layer(allocator, entry.getKey(), entry.getValue())))
|
||||
.collect(ImmutableMap.toImmutableMap(Pair::first, Pair::second));
|
||||
|
||||
|
||||
return layers;
|
||||
.map(entry -> new Layer(entry.getKey(), entry.getValue()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private class Layer implements Renderable {
|
||||
|
@ -42,14 +50,25 @@ public class InstancedModel<D extends InstanceData> {
|
|||
MeshPool.BufferedMesh bufferedMesh;
|
||||
GlVertexArray vao;
|
||||
|
||||
private Layer(MeshPool allocator, Material material, Mesh mesh) {
|
||||
private Layer(Material material, Mesh mesh) {
|
||||
this.material = material;
|
||||
vao = new GlVertexArray();
|
||||
bufferedMesh = allocator.alloc(mesh);
|
||||
bufferedMesh = MeshPool.getInstance()
|
||||
.alloc(mesh);
|
||||
instancer.attributeBaseIndex = bufferedMesh.getAttributeCount();
|
||||
vao.enableArrays(bufferedMesh.getAttributeCount() + instancer.instanceFormat.getAttributeCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexType getVertexType() {
|
||||
return bufferedMesh.getVertexType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
if (invalid()) return;
|
||||
|
@ -61,9 +80,6 @@ public class InstancedModel<D extends InstanceData> {
|
|||
if (instancer.glInstanceCount > 0) {
|
||||
bufferedMesh.drawInstances(vao, instancer.glInstanceCount);
|
||||
}
|
||||
|
||||
// persistent mapping sync point
|
||||
instancer.vbo.doneForThisFrame();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,6 +88,9 @@ public class InstancedModel<D extends InstanceData> {
|
|||
return invalid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Only {@code true} if the InstancedModel has been destroyed.
|
||||
*/
|
||||
private boolean invalid() {
|
||||
return instancer.vbo == null || bufferedMesh == null || vao == null;
|
||||
}
|
||||
|
@ -105,7 +124,7 @@ public class InstancedModel<D extends InstanceData> {
|
|||
instancer.vbo.delete();
|
||||
instancer.vbo = null;
|
||||
|
||||
for (var layer : layers.values()) {
|
||||
for (var layer : layers) {
|
||||
layer.delete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +1,59 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.backend.instancing.Engine;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceManager;
|
||||
import com.jozufozu.flywheel.backend.model.MeshPool;
|
||||
import com.jozufozu.flywheel.core.CoreShaderInfoMap;
|
||||
import com.jozufozu.flywheel.core.Contexts;
|
||||
import com.jozufozu.flywheel.core.CoreShaderInfoMap.CoreShaderInfo;
|
||||
import com.jozufozu.flywheel.core.GameStateRegistry;
|
||||
import com.jozufozu.flywheel.core.RenderContext;
|
||||
import com.jozufozu.flywheel.core.compile.ProgramCompiler;
|
||||
import com.jozufozu.flywheel.core.crumbling.CrumblingProgram;
|
||||
import com.jozufozu.flywheel.core.model.Mesh;
|
||||
import com.jozufozu.flywheel.core.model.ModelSupplier;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.core.vertex.Formats;
|
||||
import com.jozufozu.flywheel.mixin.LevelRendererAccessor;
|
||||
import com.jozufozu.flywheel.util.Textures;
|
||||
import com.jozufozu.flywheel.util.WeakHashSet;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.LevelRenderer;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.ShaderInstance;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.server.level.BlockDestructionProgress;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class InstancingEngine<P extends WorldProgram> implements Engine {
|
||||
|
||||
|
@ -41,11 +62,10 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
protected BlockPos originCoordinate = BlockPos.ZERO;
|
||||
|
||||
protected final ProgramCompiler<P> context;
|
||||
private MeshPool allocator;
|
||||
|
||||
protected final Map<StructType<? extends InstanceData>, GPUInstancerFactory<?>> factories = new HashMap<>();
|
||||
protected final Map<StructType<? extends InstancedPart>, GPUInstancerFactory<?>> factories = new HashMap<>();
|
||||
|
||||
protected final Set<RenderType> toRender = new HashSet<>();
|
||||
protected final Set<RenderType> layersToProcess = new HashSet<>();
|
||||
|
||||
private final WeakHashSet<OriginShiftListener> listeners;
|
||||
private int vertexCount;
|
||||
|
@ -60,7 +80,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
@SuppressWarnings("unchecked")
|
||||
@NotNull
|
||||
@Override
|
||||
public <D extends InstanceData> GPUInstancerFactory<D> factory(StructType<D> type) {
|
||||
public <D extends InstancedPart> GPUInstancerFactory<D> factory(StructType<D> type) {
|
||||
return (GPUInstancerFactory<D>) factories.computeIfAbsent(type, GPUInstancerFactory::new);
|
||||
}
|
||||
|
||||
|
@ -74,14 +94,18 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
var vp = context.viewProjection().copy();
|
||||
vp.multiplyWithTranslation((float) -camX, (float) -camY, (float) -camZ);
|
||||
|
||||
for (RenderType renderType : toRender) {
|
||||
for (RenderType renderType : layersToProcess) {
|
||||
render(renderType, camX, camY, camZ, vp, context.level());
|
||||
}
|
||||
toRender.clear();
|
||||
layersToProcess.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderSpecificType(TaskEngine taskEngine, RenderContext context, RenderType type) {
|
||||
if (!layersToProcess.remove(type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var camX = context.camX() - originCoordinate.getX();
|
||||
var camY = context.camY() - originCoordinate.getY();
|
||||
var camZ = context.camZ() - originCoordinate.getZ();
|
||||
|
@ -90,10 +114,8 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
var vp = context.viewProjection().copy();
|
||||
vp.multiplyWithTranslation((float) -camX, (float) -camY, (float) -camZ);
|
||||
|
||||
if (toRender.remove(type)) {
|
||||
render(type, camX, camY, camZ, vp, context.level());
|
||||
}
|
||||
}
|
||||
|
||||
protected void render(RenderType type, double camX, double camY, double camZ, Matrix4f viewProjection, ClientLevel level) {
|
||||
vertexCount = 0;
|
||||
|
@ -101,55 +123,36 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
|
||||
type.setupRenderState();
|
||||
Textures.bindActiveTextures();
|
||||
CoreShaderInfo coreShaderInfo = getCoreShaderInfo();
|
||||
CoreShaderInfo coreShaderInfo = CoreShaderInfo.get();
|
||||
|
||||
for (var entry : factories.entrySet()) {
|
||||
var instanceType = entry.getKey();
|
||||
var factory = entry.getValue();
|
||||
|
||||
var materials = factory.materials.get(type);
|
||||
for (Material material : materials) {
|
||||
var toRender = factory.renderables.get(material);
|
||||
toRender.removeIf(Renderable::shouldRemove);
|
||||
var toRender = factory.getRenderList(type);
|
||||
|
||||
if (!toRender.isEmpty()) {
|
||||
setup(instanceType, material, coreShaderInfo, camX, camY, camZ, viewProjection, level);
|
||||
if (toRender.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Renderable renderable : toRender) {
|
||||
setup(instanceType, renderable.getMaterial(), coreShaderInfo, camX, camY, camZ, viewProjection, level, renderable.getVertexType());
|
||||
|
||||
renderable.render();
|
||||
}
|
||||
|
||||
instanceCount += factory.getInstanceCount();
|
||||
vertexCount += factory.getVertexCount();
|
||||
|
||||
toRender.forEach(Renderable::render);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type.clearRenderState();
|
||||
}
|
||||
|
||||
protected CoreShaderInfo getCoreShaderInfo() {
|
||||
CoreShaderInfo coreShaderInfo;
|
||||
ShaderInstance coreShader = RenderSystem.getShader();
|
||||
if (coreShader != null) {
|
||||
String coreShaderName = coreShader.getName();
|
||||
coreShaderInfo = CoreShaderInfoMap.getInfo(coreShaderName);
|
||||
} else {
|
||||
coreShaderInfo = null;
|
||||
}
|
||||
if (coreShaderInfo == null) {
|
||||
coreShaderInfo = CoreShaderInfo.DEFAULT;
|
||||
}
|
||||
return coreShaderInfo;
|
||||
}
|
||||
protected P setup(StructType<?> instanceType, Material material, CoreShaderInfo coreShaderInfo, double camX, double camY, double camZ, Matrix4f viewProjection, ClientLevel level, VertexType vertexType) {
|
||||
|
||||
protected P setup(StructType<?> instanceType, Material material, CoreShaderInfo coreShaderInfo, double camX, double camY, double camZ, Matrix4f viewProjection, ClientLevel level) {
|
||||
float alphaDiscard = coreShaderInfo.alphaDiscard();
|
||||
if (alphaDiscard == 0) {
|
||||
alphaDiscard = 0.0001f;
|
||||
} else if (alphaDiscard < 0) {
|
||||
alphaDiscard = 0;
|
||||
}
|
||||
|
||||
P program = context.getProgram(new ProgramCompiler.Context(Formats.POS_TEX_NORMAL, instanceType.getInstanceShader(), material.getVertexShader(), material.getFragmentShader(), alphaDiscard, coreShaderInfo.fogType(), GameStateRegistry.takeSnapshot()));
|
||||
P program = context.getProgram(new ProgramCompiler.Context(vertexType, instanceType.getInstanceShader(),
|
||||
material.getVertexShader(), material.getFragmentShader(), coreShaderInfo.getAdjustedAlphaDiscard(),
|
||||
coreShaderInfo.fogType(), GameStateRegistry.takeSnapshot()));
|
||||
|
||||
program.bind();
|
||||
program.uploadUniforms(camX, camY, camZ, viewProjection, level);
|
||||
|
@ -187,15 +190,15 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
public void beginFrame(Camera info) {
|
||||
checkOriginDistance(info);
|
||||
|
||||
MeshPool allocator = getModelAllocator();
|
||||
|
||||
for (GPUInstancerFactory<?> factory : factories.values()) {
|
||||
factory.init(allocator);
|
||||
factory.init();
|
||||
|
||||
toRender.addAll(factory.materials.keySet());
|
||||
factory.gatherLayers(layersToProcess);
|
||||
}
|
||||
|
||||
allocator.flush();
|
||||
MeshPool.getInstance()
|
||||
.flush();
|
||||
}
|
||||
|
||||
private void checkOriginDistance(Camera info) {
|
||||
|
@ -228,17 +231,130 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
info.add("Origin: " + originCoordinate.getX() + ", " + originCoordinate.getY() + ", " + originCoordinate.getZ());
|
||||
}
|
||||
|
||||
private MeshPool getModelAllocator() {
|
||||
if (allocator == null) {
|
||||
allocator = createAllocator();
|
||||
}
|
||||
return this.allocator;
|
||||
public void renderCrumbling(LevelRenderer levelRenderer, ClientLevel level, PoseStack stack, Camera camera, Matrix4f projectionMatrix) {
|
||||
var dataByStage = getDataByStage(levelRenderer, level);
|
||||
if (dataByStage.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
private static MeshPool createAllocator() {
|
||||
var map = modelsToParts(dataByStage);
|
||||
var stateSnapshot = GameStateRegistry.takeSnapshot();
|
||||
|
||||
// FIXME: Windows AMD Drivers don't like ..BaseVertex
|
||||
return new MeshPool(Formats.POS_TEX_NORMAL);
|
||||
Vec3 cameraPosition = camera.getPosition();
|
||||
var camX = cameraPosition.x - originCoordinate.getX();
|
||||
var camY = cameraPosition.y - originCoordinate.getY();
|
||||
var camZ = cameraPosition.z - originCoordinate.getZ();
|
||||
|
||||
// don't want to mutate viewProjection
|
||||
var vp = projectionMatrix.copy();
|
||||
vp.multiplyWithTranslation((float) -camX, (float) -camY, (float) -camZ);
|
||||
|
||||
GlBuffer instanceBuffer = GlBuffer.requestPersistent(GlBufferType.ARRAY_BUFFER);
|
||||
|
||||
GlVertexArray crumblingVAO = new GlVertexArray();
|
||||
|
||||
crumblingVAO.bind();
|
||||
|
||||
// crumblingVAO.bindAttributes();
|
||||
|
||||
for (var entry : map.entrySet()) {
|
||||
var model = entry.getKey();
|
||||
var parts = entry.getValue();
|
||||
|
||||
if (parts.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
StructType<?> structType = parts.get(0).type;
|
||||
|
||||
for (var meshEntry : model.get()
|
||||
.entrySet()) {
|
||||
Material material = meshEntry.getKey();
|
||||
Mesh mesh = meshEntry.getValue();
|
||||
|
||||
MeshPool.BufferedMesh bufferedMesh = MeshPool.getInstance()
|
||||
.get(mesh);
|
||||
|
||||
if (bufferedMesh == null || !bufferedMesh.isGpuResident()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
material.getRenderType().setupRenderState();
|
||||
|
||||
CoreShaderInfo coreShaderInfo = CoreShaderInfo.get();
|
||||
|
||||
|
||||
CrumblingProgram program = Contexts.CRUMBLING.getProgram(new ProgramCompiler.Context(Formats.POS_TEX_NORMAL,
|
||||
structType.getInstanceShader(), material.getVertexShader(), material.getFragmentShader(),
|
||||
coreShaderInfo.getAdjustedAlphaDiscard(), coreShaderInfo.fogType(),
|
||||
GameStateRegistry.takeSnapshot()));
|
||||
|
||||
program.bind();
|
||||
program.uploadUniforms(camX, camY, camZ, vp, level);
|
||||
|
||||
// bufferedMesh.drawInstances();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Map<ModelSupplier, List<InstancedPart>> modelsToParts(Int2ObjectMap<List<BlockEntityInstance<?>>> dataByStage) {
|
||||
var map = new HashMap<ModelSupplier, List<InstancedPart>>();
|
||||
|
||||
for (var entry : dataByStage.int2ObjectEntrySet()) {
|
||||
RenderType currentLayer = ModelBakery.DESTROY_TYPES.get(entry.getIntKey());
|
||||
|
||||
// something about when we call this means that the textures are not ready for use on the first frame they should appear
|
||||
if (currentLayer == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var blockEntityInstance : entry.getValue()) {
|
||||
|
||||
for (var part : blockEntityInstance.getCrumblingParts()) {
|
||||
if (part.getOwner() instanceof GPUInstancer instancer) {
|
||||
|
||||
// queue the instances for copying to the crumbling instance buffer
|
||||
map.computeIfAbsent(instancer.parent.model, k -> new ArrayList<>()).add(part);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private Int2ObjectMap<List<BlockEntityInstance<?>>> getDataByStage(LevelRenderer levelRenderer, ClientLevel level) {
|
||||
var destructionProgress = ((LevelRendererAccessor) levelRenderer).flywheel$getDestructionProgress();
|
||||
if (destructionProgress.isEmpty()) {
|
||||
return Int2ObjectMaps.emptyMap();
|
||||
}
|
||||
|
||||
if (!(InstancedRenderDispatcher.getInstanceWorld(level)
|
||||
.getBlockEntityInstanceManager() instanceof BlockEntityInstanceManager beim)) {
|
||||
return Int2ObjectMaps.emptyMap();
|
||||
}
|
||||
|
||||
var dataByStage = new Int2ObjectArrayMap<List<BlockEntityInstance<?>>>();
|
||||
|
||||
for (var entry : destructionProgress.long2ObjectEntrySet()) {
|
||||
SortedSet<BlockDestructionProgress> progresses = entry.getValue();
|
||||
|
||||
if (progresses == null || progresses.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int progress = progresses.last()
|
||||
.getProgress();
|
||||
|
||||
var data = dataByStage.computeIfAbsent(progress, $ -> new ArrayList<>());
|
||||
|
||||
long pos = entry.getLongKey();
|
||||
|
||||
beim.getCrumblingInstances(pos, data);
|
||||
}
|
||||
|
||||
return dataByStage;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
|
||||
public interface Renderable {
|
||||
|
||||
void render();
|
||||
|
||||
boolean shouldRemove();
|
||||
|
||||
Material getMaterial();
|
||||
|
||||
VertexType getVertexType();
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
|||
|
||||
public class ElementBuffer {
|
||||
|
||||
private final GlBuffer buffer;
|
||||
public final GlBuffer buffer;
|
||||
public final int elementCount;
|
||||
public final GlNumericType eboIndexType;
|
||||
|
||||
|
@ -14,12 +14,4 @@ public class ElementBuffer {
|
|||
this.eboIndexType = indexType;
|
||||
this.elementCount = elementCount;
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
buffer.bind();
|
||||
}
|
||||
|
||||
public void unbind() {
|
||||
buffer.unbind();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,50 +1,65 @@
|
|||
package com.jozufozu.flywheel.backend.model;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexWriter;
|
||||
import com.jozufozu.flywheel.backend.gl.GlPrimitive;
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
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.gl.buffer.MappedGlBuffer;
|
||||
import com.jozufozu.flywheel.core.layout.BufferLayout;
|
||||
import com.jozufozu.flywheel.core.model.Mesh;
|
||||
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
||||
|
||||
public class MeshPool {
|
||||
|
||||
protected final VertexType vertexType;
|
||||
private static MeshPool allocator;
|
||||
|
||||
private final List<BufferedMesh> models = new ArrayList<>();
|
||||
public static MeshPool getInstance() {
|
||||
if (allocator == null) {
|
||||
allocator = new MeshPool();
|
||||
}
|
||||
return allocator;
|
||||
}
|
||||
|
||||
public static void reset(ReloadRenderersEvent ignored) {
|
||||
if (allocator != null) {
|
||||
allocator.delete();
|
||||
allocator = null;
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<Mesh, BufferedMesh> meshes = new HashMap<>();
|
||||
private final List<BufferedMesh> allBuffered = new ArrayList<>();
|
||||
|
||||
private final List<BufferedMesh> pendingUpload = new ArrayList<>();
|
||||
|
||||
private final GlBuffer vbo;
|
||||
|
||||
private int vertices;
|
||||
private long byteSize;
|
||||
|
||||
private boolean dirty;
|
||||
private boolean anyToRemove;
|
||||
|
||||
/**
|
||||
* Create a new model pool.
|
||||
*
|
||||
* @param vertexType The vertex type of the models that will be stored in the pool.
|
||||
* Create a new mesh pool.
|
||||
*/
|
||||
public MeshPool(VertexType vertexType) {
|
||||
this.vertexType = vertexType;
|
||||
int stride = vertexType.getStride();
|
||||
|
||||
public MeshPool() {
|
||||
vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER);
|
||||
|
||||
vbo.setGrowthMargin(stride * 64);
|
||||
vbo.setGrowthMargin(2048);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -54,18 +69,27 @@ public class MeshPool {
|
|||
* @return A handle to the allocated model.
|
||||
*/
|
||||
public BufferedMesh alloc(Mesh mesh) {
|
||||
BufferedMesh bufferedModel = new BufferedMesh(mesh, vertices);
|
||||
vertices += mesh.getVertexCount();
|
||||
models.add(bufferedModel);
|
||||
return meshes.computeIfAbsent(mesh, m -> {
|
||||
BufferedMesh bufferedModel = new BufferedMesh(m, byteSize);
|
||||
byteSize += m.size();
|
||||
allBuffered.add(bufferedModel);
|
||||
pendingUpload.add(bufferedModel);
|
||||
|
||||
dirty = true;
|
||||
return bufferedModel;
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BufferedMesh get(Mesh mesh) {
|
||||
return meshes.get(mesh);
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
if (dirty) {
|
||||
if (anyToRemove) processDeletions();
|
||||
if (anyToRemove) {
|
||||
processDeletions();
|
||||
}
|
||||
|
||||
if (realloc()) {
|
||||
uploadAll();
|
||||
|
@ -80,21 +104,28 @@ public class MeshPool {
|
|||
|
||||
private void processDeletions() {
|
||||
|
||||
// remove deleted models
|
||||
models.removeIf(BufferedMesh::isDeleted);
|
||||
// remove deleted meshes
|
||||
allBuffered.removeIf(bufferedMesh -> {
|
||||
boolean deleted = bufferedMesh.isDeleted();
|
||||
if (deleted) {
|
||||
meshes.remove(bufferedMesh.mesh);
|
||||
}
|
||||
return deleted;
|
||||
});
|
||||
|
||||
// re-evaluate first vertex for each model
|
||||
int vertices = 0;
|
||||
for (BufferedMesh model : models) {
|
||||
if (model.first != vertices)
|
||||
int byteIndex = 0;
|
||||
for (BufferedMesh model : allBuffered) {
|
||||
if (model.byteIndex != byteIndex) {
|
||||
pendingUpload.add(model);
|
||||
|
||||
model.first = vertices;
|
||||
|
||||
vertices += model.mesh.getVertexCount();
|
||||
}
|
||||
|
||||
this.vertices = vertices;
|
||||
model.byteIndex = byteIndex;
|
||||
|
||||
byteIndex += model.mesh.size();
|
||||
}
|
||||
|
||||
this.byteSize = byteIndex;
|
||||
this.anyToRemove = false;
|
||||
}
|
||||
|
||||
|
@ -104,20 +135,20 @@ public class MeshPool {
|
|||
* @return true if the buffer was reallocated
|
||||
*/
|
||||
private boolean realloc() {
|
||||
return vbo.ensureCapacity((long) vertices * vertexType.getStride());
|
||||
return vbo.ensureCapacity(byteSize);
|
||||
}
|
||||
|
||||
private void uploadAll() {
|
||||
try (MappedBuffer buffer = vbo.map()) {
|
||||
VertexWriter writer = vertexType.createWriter(buffer.unwrap());
|
||||
try (MappedBuffer mapped = vbo.map()) {
|
||||
ByteBuffer buffer = mapped.unwrap();
|
||||
|
||||
int vertices = 0;
|
||||
for (BufferedMesh model : models) {
|
||||
model.first = vertices;
|
||||
int byteIndex = 0;
|
||||
for (BufferedMesh model : allBuffered) {
|
||||
model.byteIndex = byteIndex;
|
||||
|
||||
model.buffer(writer);
|
||||
model.buffer(buffer);
|
||||
|
||||
vertices += model.mesh.getVertexCount();
|
||||
byteIndex += model.mesh.size();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
|
@ -126,10 +157,10 @@ public class MeshPool {
|
|||
}
|
||||
|
||||
private void uploadPending() {
|
||||
try (MappedBuffer buffer = vbo.map()) {
|
||||
VertexWriter writer = vertexType.createWriter(buffer.unwrap());
|
||||
try (MappedBuffer mapped = vbo.map()) {
|
||||
ByteBuffer buffer = mapped.unwrap();
|
||||
for (BufferedMesh model : pendingUpload) {
|
||||
model.buffer(writer);
|
||||
model.buffer(buffer);
|
||||
}
|
||||
pendingUpload.clear();
|
||||
} catch (Exception e) {
|
||||
|
@ -139,49 +170,63 @@ public class MeshPool {
|
|||
|
||||
public void delete() {
|
||||
vbo.delete();
|
||||
meshes.clear();
|
||||
allBuffered.clear();
|
||||
pendingUpload.clear();
|
||||
}
|
||||
|
||||
public class BufferedMesh {
|
||||
|
||||
private final ElementBuffer ebo;
|
||||
private final Mesh mesh;
|
||||
private int first;
|
||||
private final BufferLayout layout;
|
||||
private long byteIndex;
|
||||
|
||||
private boolean deleted;
|
||||
|
||||
private boolean gpuResident = false;
|
||||
|
||||
private final Set<GlVertexArray> boundTo = new HashSet<>();
|
||||
|
||||
public BufferedMesh(Mesh mesh, int first) {
|
||||
public BufferedMesh(Mesh mesh, long byteIndex) {
|
||||
this.mesh = mesh;
|
||||
this.first = first;
|
||||
this.byteIndex = byteIndex;
|
||||
this.ebo = mesh.createEBO();
|
||||
this.layout = mesh.getType()
|
||||
.getLayout();
|
||||
}
|
||||
|
||||
public void drawCall(GlVertexArray vao) {
|
||||
attachTo(vao);
|
||||
vao.bind();
|
||||
this.ebo.bind();
|
||||
GL32.glDrawElementsBaseVertex(GlPrimitive.TRIANGLES.glEnum, this.ebo.elementCount, this.ebo.eboIndexType.getGlEnum(), 0, this.first);
|
||||
drawInstances(vao, 1);
|
||||
}
|
||||
|
||||
public void drawInstances(GlVertexArray vao, int instanceCount) {
|
||||
if (mesh.getVertexCount() <= 0 || isDeleted()) return;
|
||||
if (hasAnythingToRender()) return;
|
||||
|
||||
attachTo(vao);
|
||||
setup(vao);
|
||||
|
||||
vao.bind();
|
||||
this.ebo.bind();
|
||||
|
||||
//Backend.log.info(StringUtil.args("drawElementsInstancedBaseVertex", GlPrimitive.TRIANGLES, ebo.elementCount, ebo.eboIndexType, 0, instanceCount, first));
|
||||
|
||||
GL32.glDrawElementsInstancedBaseVertex(GlPrimitive.TRIANGLES.glEnum, this.ebo.elementCount, this.ebo.eboIndexType.getGlEnum(), 0, instanceCount, this.first);
|
||||
draw(instanceCount);
|
||||
}
|
||||
|
||||
private void attachTo(GlVertexArray vao) {
|
||||
private boolean hasAnythingToRender() {
|
||||
return mesh.getVertexCount() <= 0 || isDeleted();
|
||||
}
|
||||
|
||||
private void draw(int instanceCount) {
|
||||
if (instanceCount > 1) {
|
||||
GL32.glDrawElementsInstanced(GlPrimitive.TRIANGLES.glEnum, this.ebo.elementCount, this.ebo.eboIndexType.getGlEnum(), 0, instanceCount);
|
||||
} else {
|
||||
GL32.glDrawElements(GlPrimitive.TRIANGLES.glEnum, this.ebo.elementCount, this.ebo.eboIndexType.getGlEnum(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void setup(GlVertexArray vao) {
|
||||
if (this.boundTo.add(vao)) {
|
||||
vao.enableArrays(getAttributeCount());
|
||||
vao.bindAttributes(MeshPool.this.vbo, 0, MeshPool.this.vertexType.getLayout());
|
||||
vao.bindAttributes(MeshPool.this.vbo, 0, this.layout, this.byteIndex);
|
||||
}
|
||||
vao.bindElementArray(this.ebo.buffer);
|
||||
vao.bind();
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
|
@ -194,14 +239,23 @@ public class MeshPool {
|
|||
this.deleted = true;
|
||||
}
|
||||
|
||||
private void buffer(VertexWriter writer) {
|
||||
writer.seekToVertex(this.first);
|
||||
writer.writeVertexList(this.mesh.getReader());
|
||||
private void buffer(ByteBuffer buffer) {
|
||||
this.mesh.writeInto(buffer, this.byteIndex);
|
||||
|
||||
this.boundTo.clear();
|
||||
this.gpuResident = true;
|
||||
}
|
||||
|
||||
public int getAttributeCount() {
|
||||
return MeshPool.this.vertexType.getLayout().getAttributeCount();
|
||||
return this.layout.getAttributeCount();
|
||||
}
|
||||
|
||||
public boolean isGpuResident() {
|
||||
return gpuResident;
|
||||
}
|
||||
|
||||
public VertexType getVertexType() {
|
||||
return this.mesh.getType();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,9 @@ import java.util.Map;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.backend.OptifineHandler;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
import net.minecraft.client.renderer.ShaderInstance;
|
||||
|
||||
public class CoreShaderInfoMap {
|
||||
private static final Map<String, CoreShaderInfo> MAP = new HashMap<>();
|
||||
|
@ -86,6 +89,29 @@ public class CoreShaderInfoMap {
|
|||
public record CoreShaderInfo(float alphaDiscard, boolean appliesDiffuse, FogType fogType) {
|
||||
public static final CoreShaderInfo DEFAULT = new CoreShaderInfo(-1, false, NO_FOG);
|
||||
|
||||
public static CoreShaderInfo get() {
|
||||
CoreShaderInfo out = null;
|
||||
ShaderInstance coreShader = RenderSystem.getShader();
|
||||
if (coreShader != null) {
|
||||
String coreShaderName = coreShader.getName();
|
||||
out = getInfo(coreShaderName);
|
||||
}
|
||||
if (out == null) {
|
||||
out = DEFAULT;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public float getAdjustedAlphaDiscard() {
|
||||
float alphaDiscard = alphaDiscard();
|
||||
if (alphaDiscard == 0) {
|
||||
alphaDiscard = 0.0001f;
|
||||
} else if (alphaDiscard < 0) {
|
||||
alphaDiscard = 0;
|
||||
}
|
||||
return alphaDiscard;
|
||||
}
|
||||
|
||||
public enum FogType {
|
||||
NO_FOG,
|
||||
COLOR_FOG,
|
||||
|
|
|
@ -2,10 +2,8 @@ package com.jozufozu.flywheel.core;
|
|||
|
||||
import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
|
||||
import static org.lwjgl.opengl.GL11.glDrawArrays;
|
||||
import static org.lwjgl.opengl.GL20.glVertexAttribPointer;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.gl.GlNumericType;
|
||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||
|
@ -52,7 +50,7 @@ public class FullscreenQuad {
|
|||
|
||||
vao.enableArrays(1);
|
||||
|
||||
vao.bindAttributes(vbo, 0, LAYOUT);
|
||||
vao.bindAttributes(vbo, 0, LAYOUT, 0L);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,15 +15,9 @@ import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer;
|
|||
import com.jozufozu.flywheel.backend.model.ElementBuffer;
|
||||
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
||||
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.eventbus.api.EventPriority;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
/**
|
||||
* A class to manage EBOs that index quads as triangles.
|
||||
*/
|
||||
@Mod.EventBusSubscriber(Dist.CLIENT)
|
||||
public class QuadConverter {
|
||||
|
||||
private static QuadConverter INSTANCE;
|
||||
|
@ -42,7 +36,7 @@ public class QuadConverter {
|
|||
return INSTANCE;
|
||||
}
|
||||
|
||||
private MappedGlBuffer ebo;
|
||||
private final MappedGlBuffer ebo;
|
||||
private int quadCapacity;
|
||||
|
||||
public QuadConverter() {
|
||||
|
@ -111,7 +105,6 @@ public class QuadConverter {
|
|||
}
|
||||
|
||||
// make sure this gets reset first so it has a chance to repopulate
|
||||
@SubscribeEvent(priority = EventPriority.HIGHEST)
|
||||
public static void onRendererReload(ReloadRenderersEvent event) {
|
||||
if (INSTANCE != null) {
|
||||
INSTANCE.delete();
|
||||
|
|
|
@ -4,7 +4,6 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
|
||||
|
@ -34,15 +33,11 @@ import net.minecraft.core.BlockPos;
|
|||
import net.minecraft.server.level.BlockDestructionProgress;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
// TODO: merge directly into InstancingEngine for efficiency
|
||||
/**
|
||||
* Responsible for rendering the crumbling overlay for instanced block entities.
|
||||
*/
|
||||
@Mod.EventBusSubscriber(Dist.CLIENT)
|
||||
public class CrumblingRenderer {
|
||||
|
||||
private static Lazy<State> STATE;
|
||||
|
@ -128,7 +123,6 @@ public class CrumblingRenderer {
|
|||
return breakingEntities;
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onReloadRenderers(ReloadRenderersEvent event) {
|
||||
ClientLevel world = event.getWorld();
|
||||
if (Backend.isOn() && world != null) {
|
||||
|
@ -176,23 +170,25 @@ public class CrumblingRenderer {
|
|||
|
||||
currentLayer.setupRenderState();
|
||||
Textures.bindActiveTextures();
|
||||
CoreShaderInfo coreShaderInfo = getCoreShaderInfo();
|
||||
CoreShaderInfo coreShaderInfo = CoreShaderInfo.get();
|
||||
|
||||
for (var entry : factories.entrySet()) {
|
||||
var instanceType = entry.getKey();
|
||||
var factory = entry.getValue();
|
||||
|
||||
var materials = factory.materials.get(type);
|
||||
for (Material material : materials) {
|
||||
var toRender = factory.renderables.get(material);
|
||||
toRender.removeIf(Renderable::shouldRemove);
|
||||
var toRender = factory.getRenderList(type);
|
||||
|
||||
if (!toRender.isEmpty()) {
|
||||
setup(instanceType, material, coreShaderInfo, camX, camY, camZ, viewProjection, level);
|
||||
if (toRender.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
toRender.forEach(Renderable::render);
|
||||
}
|
||||
for (var renderable : toRender) {
|
||||
|
||||
setup(instanceType, renderable.getMaterial(), coreShaderInfo, camX, camY, camZ, viewProjection, level, renderable.getVertexType());
|
||||
|
||||
renderable.render();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
currentLayer.clearRenderState();
|
||||
|
|
|
@ -34,7 +34,7 @@ public class ModelPart implements Mesh {
|
|||
cuboid.buffer(writer);
|
||||
}
|
||||
|
||||
reader = writer.intoReader();
|
||||
reader = writer.intoReader(this.vertices);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,10 +5,10 @@ import java.util.function.Consumer;
|
|||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.Instancer;
|
||||
|
||||
public class ConditionalInstance<D extends InstanceData> {
|
||||
public class ConditionalInstance<D extends InstancedPart> {
|
||||
|
||||
final Instancer<D> model;
|
||||
ICondition condition;
|
||||
|
|
|
@ -5,10 +5,10 @@ import java.util.ArrayList;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.Instancer;
|
||||
|
||||
public class GroupInstance<D extends InstanceData> extends AbstractCollection<D> {
|
||||
public class GroupInstance<D extends InstancedPart> extends AbstractCollection<D> {
|
||||
|
||||
final Instancer<D> model;
|
||||
final List<D> backing;
|
||||
|
@ -48,14 +48,14 @@ public class GroupInstance<D extends InstanceData> extends AbstractCollection<D>
|
|||
}
|
||||
} else {
|
||||
List<D> unnecessary = backing.subList(count, size);
|
||||
unnecessary.forEach(InstanceData::delete);
|
||||
unnecessary.forEach(InstancedPart::delete);
|
||||
unnecessary.clear();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public InstanceData addInstance() {
|
||||
public InstancedPart addInstance() {
|
||||
D instance = model.createInstance();
|
||||
backing.add(instance);
|
||||
|
||||
|
@ -78,7 +78,7 @@ public class GroupInstance<D extends InstanceData> extends AbstractCollection<D>
|
|||
|
||||
@Override
|
||||
public void clear() {
|
||||
backing.forEach(InstanceData::delete);
|
||||
backing.forEach(InstancedPart::delete);
|
||||
backing.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@ import java.util.Optional;
|
|||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.Instancer;
|
||||
|
||||
public class SelectInstance<D extends InstanceData> {
|
||||
public class SelectInstance<D extends InstancedPart> {
|
||||
|
||||
final List<Instancer<D>> models;
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.nio.ByteBuffer;
|
|||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexWriter;
|
||||
import com.jozufozu.flywheel.backend.model.ElementBuffer;
|
||||
import com.jozufozu.flywheel.core.QuadConverter;
|
||||
|
||||
|
@ -77,7 +78,9 @@ public interface Mesh {
|
|||
return getVertexCount() == 0;
|
||||
}
|
||||
|
||||
default void writeInto(ByteBuffer buffer) {
|
||||
getType().createWriter(buffer).writeVertexList(getReader());
|
||||
default void writeInto(ByteBuffer buffer, long byteIndex) {
|
||||
VertexWriter writer = getType().createWriter(buffer);
|
||||
writer.seek(byteIndex);
|
||||
writer.writeVertexList(getReader());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package com.jozufozu.flywheel.core.structs;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.util.Color;
|
||||
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
|
||||
public abstract class BasicData extends InstanceData implements FlatLit<BasicData> {
|
||||
public abstract class ColoredLitPart extends InstancedPart implements FlatLit<ColoredLitPart> {
|
||||
|
||||
public byte blockLight;
|
||||
public byte skyLight;
|
||||
|
@ -15,15 +16,19 @@ public abstract class BasicData extends InstanceData implements FlatLit<BasicDat
|
|||
public byte b = (byte) 0xFF;
|
||||
public byte a = (byte) 0xFF;
|
||||
|
||||
public ColoredLitPart(StructType<?> type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicData setBlockLight(int blockLight) {
|
||||
public ColoredLitPart setBlockLight(int blockLight) {
|
||||
this.blockLight = (byte) blockLight;
|
||||
markDirty();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicData setSkyLight(int skyLight) {
|
||||
public ColoredLitPart setSkyLight(int skyLight) {
|
||||
this.skyLight = (byte) skyLight;
|
||||
markDirty();
|
||||
return this;
|
||||
|
@ -34,7 +39,7 @@ public abstract class BasicData extends InstanceData implements FlatLit<BasicDat
|
|||
return LightTexture.pack(this.blockLight, this.skyLight);
|
||||
}
|
||||
|
||||
public BasicData setColor(Color color) {
|
||||
public ColoredLitPart setColor(Color color) {
|
||||
this.r = (byte) color.getRed();
|
||||
this.g = (byte) color.getGreen();
|
||||
this.b = (byte) color.getBlue();
|
||||
|
@ -43,11 +48,11 @@ public abstract class BasicData extends InstanceData implements FlatLit<BasicDat
|
|||
return this;
|
||||
}
|
||||
|
||||
public BasicData setColor(int color) {
|
||||
public ColoredLitPart setColor(int color) {
|
||||
return setColor(color, false);
|
||||
}
|
||||
|
||||
public BasicData setColor(int color, boolean alpha) {
|
||||
public ColoredLitPart setColor(int color, boolean alpha) {
|
||||
byte r = (byte) ((color >> 16) & 0xFF);
|
||||
byte g = (byte) ((color >> 8) & 0xFF);
|
||||
byte b = (byte) (color & 0xFF);
|
||||
|
@ -60,11 +65,11 @@ public abstract class BasicData extends InstanceData implements FlatLit<BasicDat
|
|||
}
|
||||
}
|
||||
|
||||
public BasicData setColor(int r, int g, int b) {
|
||||
public ColoredLitPart setColor(int r, int g, int b) {
|
||||
return setColor((byte) r, (byte) g, (byte) b);
|
||||
}
|
||||
|
||||
public BasicData setColor(byte r, byte g, byte b) {
|
||||
public ColoredLitPart setColor(byte r, byte g, byte b) {
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
|
@ -72,7 +77,7 @@ public abstract class BasicData extends InstanceData implements FlatLit<BasicDat
|
|||
return this;
|
||||
}
|
||||
|
||||
public BasicData setColor(byte r, byte g, byte b, byte a) {
|
||||
public ColoredLitPart setColor(byte r, byte g, byte b, byte a) {
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
|
@ -80,5 +85,4 @@ public abstract class BasicData extends InstanceData implements FlatLit<BasicDat
|
|||
markDirty();
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
|
@ -7,9 +7,9 @@ import org.lwjgl.system.MemoryUtil;
|
|||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.struct.UnsafeBufferWriter;
|
||||
|
||||
public abstract class BasicWriterUnsafe<D extends BasicData> extends UnsafeBufferWriter<D> {
|
||||
public abstract class ColoredLitWriterUnsafe<D extends ColoredLitPart> extends UnsafeBufferWriter<D> {
|
||||
|
||||
public BasicWriterUnsafe(StructType<D> structType, ByteBuffer byteBuffer) {
|
||||
public ColoredLitWriterUnsafe(StructType<D> structType, ByteBuffer byteBuffer) {
|
||||
super(structType, byteBuffer);
|
||||
}
|
||||
|
|
@ -1,20 +1,20 @@
|
|||
package com.jozufozu.flywheel.core.structs;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
|
||||
/**
|
||||
* An interface that implementors of {@link InstanceData} should also implement
|
||||
* An interface that implementors of {@link InstancedPart} 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.
|
||||
*/
|
||||
public interface FlatLit<D extends InstanceData & FlatLit<D>> {
|
||||
public interface FlatLit<D extends InstancedPart & FlatLit<D>> {
|
||||
/**
|
||||
* @param blockLight An integer in the range [0, 15] representing the
|
||||
* amount of block light this instance should receive.
|
||||
|
|
|
@ -14,7 +14,7 @@ import net.minecraft.resources.ResourceLocation;
|
|||
public class InstanceShaders {
|
||||
public static final BiConsumer<ErrorReporter, SourceFile> CHECK = SourceChecks.checkFunctionParameterTypeExists("flw_instanceVertex", 1, 0);
|
||||
|
||||
public static final FileResolution MODEL = create(ResourceUtil.subPath(Names.MODEL, ".vert"));
|
||||
public static final FileResolution TRANSFORMED = create(ResourceUtil.subPath(Names.TRANSFORMED, ".vert"));
|
||||
public static final FileResolution ORIENTED = create(ResourceUtil.subPath(Names.ORIENTED, ".vert"));
|
||||
|
||||
public static FileResolution create(ResourceLocation location) {
|
||||
|
@ -25,7 +25,7 @@ public class InstanceShaders {
|
|||
}
|
||||
|
||||
public static class Names {
|
||||
public static final ResourceLocation MODEL = Flywheel.rl("instance/model");
|
||||
public static final ResourceLocation TRANSFORMED = Flywheel.rl("instance/transformed");
|
||||
public static final ResourceLocation ORIENTED = Flywheel.rl("instance/oriented");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package com.jozufozu.flywheel.core.structs;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.core.structs.model.ModelData;
|
||||
import com.jozufozu.flywheel.core.structs.model.ModelType;
|
||||
import com.jozufozu.flywheel.core.structs.oriented.OrientedData;
|
||||
import com.jozufozu.flywheel.core.structs.model.TransformedPart;
|
||||
import com.jozufozu.flywheel.core.structs.model.TransformedType;
|
||||
import com.jozufozu.flywheel.core.structs.oriented.OrientedPart;
|
||||
import com.jozufozu.flywheel.core.structs.oriented.OrientedType;
|
||||
|
||||
public class StructTypes {
|
||||
public static final StructType<ModelData> MODEL = new ModelType();
|
||||
public static final StructType<OrientedData> ORIENTED = new OrientedType();
|
||||
public static final StructType<TransformedPart> TRANSFORMED = new TransformedType();
|
||||
public static final StructType<OrientedPart> ORIENTED = new OrientedType();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.jozufozu.flywheel.core.structs.model;
|
||||
|
||||
import com.jozufozu.flywheel.core.structs.BasicData;
|
||||
import com.jozufozu.flywheel.core.structs.ColoredLitPart;
|
||||
import com.jozufozu.flywheel.core.structs.StructTypes;
|
||||
import com.jozufozu.flywheel.util.transform.Transform;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Matrix3f;
|
||||
|
@ -9,14 +10,18 @@ import com.mojang.math.Quaternion;
|
|||
|
||||
import net.minecraft.util.Mth;
|
||||
|
||||
public class ModelData extends BasicData implements Transform<ModelData> {
|
||||
public class TransformedPart extends ColoredLitPart implements Transform<TransformedPart> {
|
||||
private static final Matrix4f EMPTY_MATRIX_4f = new Matrix4f();
|
||||
private static final Matrix3f EMPTY_MATRIX_3f = new Matrix3f();
|
||||
|
||||
public final Matrix4f model = new Matrix4f();
|
||||
public final Matrix3f normal = new Matrix3f();
|
||||
|
||||
public ModelData setTransform(PoseStack stack) {
|
||||
public TransformedPart() {
|
||||
super(StructTypes.TRANSFORMED);
|
||||
}
|
||||
|
||||
public TransformedPart setTransform(PoseStack stack) {
|
||||
markDirty();
|
||||
|
||||
this.model.load(stack.last().pose());
|
||||
|
@ -31,7 +36,7 @@ public class ModelData extends BasicData implements Transform<ModelData> {
|
|||
* This will allow the gpu to quickly discard all geometry for this instance, effectively "turning it off".
|
||||
* </p>
|
||||
*/
|
||||
public ModelData setEmptyTransform() {
|
||||
public TransformedPart setEmptyTransform() {
|
||||
markDirty();
|
||||
|
||||
this.model.load(EMPTY_MATRIX_4f);
|
||||
|
@ -39,7 +44,7 @@ public class ModelData extends BasicData implements Transform<ModelData> {
|
|||
return this;
|
||||
}
|
||||
|
||||
public ModelData loadIdentity() {
|
||||
public TransformedPart loadIdentity() {
|
||||
markDirty();
|
||||
|
||||
this.model.setIdentity();
|
||||
|
@ -48,7 +53,7 @@ public class ModelData extends BasicData implements Transform<ModelData> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ModelData multiply(Quaternion quaternion) {
|
||||
public TransformedPart multiply(Quaternion quaternion) {
|
||||
markDirty();
|
||||
|
||||
model.multiply(quaternion);
|
||||
|
@ -57,7 +62,7 @@ public class ModelData extends BasicData implements Transform<ModelData> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ModelData scale(float pX, float pY, float pZ) {
|
||||
public TransformedPart scale(float pX, float pY, float pZ) {
|
||||
markDirty();
|
||||
|
||||
model.multiply(Matrix4f.createScaleMatrix(pX, pY, pZ));
|
||||
|
@ -79,7 +84,7 @@ public class ModelData extends BasicData implements Transform<ModelData> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ModelData translate(double x, double y, double z) {
|
||||
public TransformedPart translate(double x, double y, double z) {
|
||||
markDirty();
|
||||
|
||||
model.multiplyWithTranslation((float) x, (float) y, (float) z);
|
||||
|
@ -87,14 +92,28 @@ public class ModelData extends BasicData implements Transform<ModelData> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ModelData mulPose(Matrix4f pose) {
|
||||
public TransformedPart mulPose(Matrix4f pose) {
|
||||
this.model.multiply(pose);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelData mulNormal(Matrix3f normal) {
|
||||
public TransformedPart mulNormal(Matrix3f normal) {
|
||||
this.normal.mul(normal);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformedPart copy() {
|
||||
var out = new TransformedPart();
|
||||
out.model.load(this.model);
|
||||
out.normal.load(this.normal);
|
||||
out.r = this.r;
|
||||
out.g = this.g;
|
||||
out.b = this.b;
|
||||
out.a = this.a;
|
||||
out.blockLight = this.blockLight;
|
||||
out.skyLight = this.skyLight;
|
||||
return out;
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ import com.jozufozu.flywheel.core.model.ModelTransformer;
|
|||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.structs.InstanceShaders;
|
||||
|
||||
public class ModelType implements StructType<ModelData> {
|
||||
public class TransformedType implements StructType<TransformedPart> {
|
||||
|
||||
public static final BufferLayout FORMAT = BufferLayout.builder()
|
||||
.addItems(CommonItems.LIGHT, CommonItems.RGBA)
|
||||
|
@ -18,8 +18,8 @@ public class ModelType implements StructType<ModelData> {
|
|||
.build();
|
||||
|
||||
@Override
|
||||
public ModelData create() {
|
||||
return new ModelData();
|
||||
public TransformedPart create() {
|
||||
return new TransformedPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -28,17 +28,17 @@ public class ModelType implements StructType<ModelData> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public StructWriter<ModelData> getWriter(ByteBuffer backing) {
|
||||
return new ModelWriterUnsafe(this, backing);
|
||||
public StructWriter<TransformedPart> getWriter(ByteBuffer backing) {
|
||||
return new TransformedWriterUnsafe(this, backing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileResolution getInstanceShader() {
|
||||
return InstanceShaders.MODEL;
|
||||
return InstanceShaders.TRANSFORMED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(ModelData d, ModelTransformer.Params b) {
|
||||
public void transform(TransformedPart d, ModelTransformer.Params b) {
|
||||
b.transform(d.model, d.normal)
|
||||
.color(d.r, d.g, d.b, d.a)
|
||||
.light(d.getPackedLight());
|
|
@ -3,17 +3,17 @@ package com.jozufozu.flywheel.core.structs.model;
|
|||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.core.structs.BasicWriterUnsafe;
|
||||
import com.jozufozu.flywheel.core.structs.ColoredLitWriterUnsafe;
|
||||
import com.jozufozu.flywheel.util.MatrixWrite;
|
||||
|
||||
public class ModelWriterUnsafe extends BasicWriterUnsafe<ModelData> {
|
||||
public class TransformedWriterUnsafe extends ColoredLitWriterUnsafe<TransformedPart> {
|
||||
|
||||
public ModelWriterUnsafe(StructType<ModelData> structType, ByteBuffer byteBuffer) {
|
||||
public TransformedWriterUnsafe(StructType<TransformedPart> structType, ByteBuffer byteBuffer) {
|
||||
super(structType, byteBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeInternal(ModelData d) {
|
||||
protected void writeInternal(TransformedPart d) {
|
||||
super.writeInternal(d);
|
||||
long ptr = writePointer + 6;
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.structs.oriented;
|
||||
|
||||
import com.jozufozu.flywheel.core.structs.BasicData;
|
||||
import com.mojang.math.Quaternion;
|
||||
import com.mojang.math.Vector3f;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
public class OrientedData extends BasicData {
|
||||
|
||||
public float posX;
|
||||
public float posY;
|
||||
public float posZ;
|
||||
public float pivotX = 0.5f;
|
||||
public float pivotY = 0.5f;
|
||||
public float pivotZ = 0.5f;
|
||||
public float qX;
|
||||
public float qY;
|
||||
public float qZ;
|
||||
public float qW = 1;
|
||||
|
||||
public OrientedData setPosition(BlockPos pos) {
|
||||
return setPosition(pos.getX(), pos.getY(), pos.getZ());
|
||||
}
|
||||
|
||||
public OrientedData setPosition(Vector3f pos) {
|
||||
return setPosition(pos.x(), pos.y(), pos.z());
|
||||
}
|
||||
|
||||
public OrientedData setPosition(float x, float y, float z) {
|
||||
this.posX = x;
|
||||
this.posY = y;
|
||||
this.posZ = z;
|
||||
markDirty();
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrientedData nudge(float x, float y, float z) {
|
||||
this.posX += x;
|
||||
this.posY += y;
|
||||
this.posZ += z;
|
||||
markDirty();
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrientedData setPivot(Vector3f pos) {
|
||||
return setPosition(pos.x(), pos.y(), pos.z());
|
||||
}
|
||||
|
||||
public OrientedData setPivot(net.minecraft.world.phys.Vec3 pos) {
|
||||
return setPosition((float) pos.x(), (float) pos.y(), (float) pos.z());
|
||||
}
|
||||
|
||||
public OrientedData setPivot(float x, float y, float z) {
|
||||
this.pivotX = x;
|
||||
this.pivotY = y;
|
||||
this.pivotZ = z;
|
||||
markDirty();
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrientedData setRotation(Quaternion q) {
|
||||
return setRotation(q.i(), q.j(), q.k(), q.r());
|
||||
}
|
||||
|
||||
public OrientedData setRotation(float x, float y, float z, float w) {
|
||||
this.qX = x;
|
||||
this.qY = y;
|
||||
this.qZ = z;
|
||||
this.qW = w;
|
||||
markDirty();
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrientedData resetRotation() {
|
||||
this.qX = 0;
|
||||
this.qY = 0;
|
||||
this.qZ = 0;
|
||||
this.qW = 1;
|
||||
markDirty();
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
package com.jozufozu.flywheel.core.structs.oriented;
|
||||
|
||||
import com.jozufozu.flywheel.core.structs.ColoredLitPart;
|
||||
import com.jozufozu.flywheel.core.structs.StructTypes;
|
||||
import com.mojang.math.Quaternion;
|
||||
import com.mojang.math.Vector3f;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
public class OrientedPart extends ColoredLitPart {
|
||||
|
||||
public float posX;
|
||||
public float posY;
|
||||
public float posZ;
|
||||
public float pivotX = 0.5f;
|
||||
public float pivotY = 0.5f;
|
||||
public float pivotZ = 0.5f;
|
||||
public float qX;
|
||||
public float qY;
|
||||
public float qZ;
|
||||
public float qW = 1;
|
||||
|
||||
public OrientedPart() {
|
||||
super(StructTypes.ORIENTED);
|
||||
}
|
||||
|
||||
public OrientedPart setPosition(BlockPos pos) {
|
||||
return setPosition(pos.getX(), pos.getY(), pos.getZ());
|
||||
}
|
||||
|
||||
public OrientedPart setPosition(Vector3f pos) {
|
||||
return setPosition(pos.x(), pos.y(), pos.z());
|
||||
}
|
||||
|
||||
public OrientedPart setPosition(float x, float y, float z) {
|
||||
this.posX = x;
|
||||
this.posY = y;
|
||||
this.posZ = z;
|
||||
markDirty();
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrientedPart nudge(float x, float y, float z) {
|
||||
this.posX += x;
|
||||
this.posY += y;
|
||||
this.posZ += z;
|
||||
markDirty();
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrientedPart setPivot(Vector3f pos) {
|
||||
return setPosition(pos.x(), pos.y(), pos.z());
|
||||
}
|
||||
|
||||
public OrientedPart setPivot(net.minecraft.world.phys.Vec3 pos) {
|
||||
return setPosition((float) pos.x(), (float) pos.y(), (float) pos.z());
|
||||
}
|
||||
|
||||
public OrientedPart setPivot(float x, float y, float z) {
|
||||
this.pivotX = x;
|
||||
this.pivotY = y;
|
||||
this.pivotZ = z;
|
||||
markDirty();
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrientedPart setRotation(Quaternion q) {
|
||||
return setRotation(q.i(), q.j(), q.k(), q.r());
|
||||
}
|
||||
|
||||
public OrientedPart setRotation(float x, float y, float z, float w) {
|
||||
this.qX = x;
|
||||
this.qY = y;
|
||||
this.qZ = z;
|
||||
this.qW = w;
|
||||
markDirty();
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrientedPart resetRotation() {
|
||||
this.qX = 0;
|
||||
this.qY = 0;
|
||||
this.qZ = 0;
|
||||
this.qW = 1;
|
||||
markDirty();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrientedPart copy() {
|
||||
var out = new OrientedPart();
|
||||
out.posX = this.posX;
|
||||
out.posY = this.posY;
|
||||
out.posZ = this.posZ;
|
||||
out.pivotX = this.pivotX;
|
||||
out.pivotY = this.pivotY;
|
||||
out.pivotZ = this.pivotZ;
|
||||
out.qX = this.qX;
|
||||
out.qY = this.qY;
|
||||
out.qZ = this.qZ;
|
||||
out.qW = this.qW;
|
||||
out.r = this.r;
|
||||
out.g = this.g;
|
||||
out.b = this.b;
|
||||
out.a = this.a;
|
||||
out.blockLight = this.blockLight;
|
||||
out.skyLight = this.skyLight;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ import com.jozufozu.flywheel.core.source.FileResolution;
|
|||
import com.jozufozu.flywheel.core.structs.InstanceShaders;
|
||||
import com.mojang.math.Quaternion;
|
||||
|
||||
public class OrientedType implements StructType<OrientedData> {
|
||||
public class OrientedType implements StructType<OrientedPart> {
|
||||
|
||||
public static final BufferLayout FORMAT = BufferLayout.builder()
|
||||
.addItems(CommonItems.LIGHT, CommonItems.RGBA)
|
||||
|
@ -19,8 +19,8 @@ public class OrientedType implements StructType<OrientedData> {
|
|||
.build();
|
||||
|
||||
@Override
|
||||
public OrientedData create() {
|
||||
return new OrientedData();
|
||||
public OrientedPart create() {
|
||||
return new OrientedPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -29,7 +29,7 @@ public class OrientedType implements StructType<OrientedData> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public StructWriter<OrientedData> getWriter(ByteBuffer backing) {
|
||||
public StructWriter<OrientedPart> getWriter(ByteBuffer backing) {
|
||||
return new OrientedWriterUnsafe(this, backing);
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ public class OrientedType implements StructType<OrientedData> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void transform(OrientedData d, ModelTransformer.Params b) {
|
||||
public void transform(OrientedPart d, ModelTransformer.Params b) {
|
||||
b.light(d.getPackedLight())
|
||||
.color(d.r, d.g, d.b, d.a)
|
||||
.translate(d.posX + d.pivotX, d.posY + d.pivotY, d.posZ + d.pivotZ)
|
||||
|
|
|
@ -5,15 +5,15 @@ import java.nio.ByteBuffer;
|
|||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.core.structs.BasicWriterUnsafe;
|
||||
import com.jozufozu.flywheel.core.structs.ColoredLitWriterUnsafe;
|
||||
|
||||
public class OrientedWriterUnsafe extends BasicWriterUnsafe<OrientedData> {
|
||||
public OrientedWriterUnsafe(StructType<OrientedData> structType, ByteBuffer byteBuffer) {
|
||||
public class OrientedWriterUnsafe extends ColoredLitWriterUnsafe<OrientedPart> {
|
||||
public OrientedWriterUnsafe(StructType<OrientedPart> structType, ByteBuffer byteBuffer) {
|
||||
super(structType, byteBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeInternal(OrientedData d) {
|
||||
protected void writeInternal(OrientedPart d) {
|
||||
long ptr = writePointer;
|
||||
super.writeInternal(d);
|
||||
|
||||
|
|
|
@ -52,6 +52,5 @@ public class BlockWriterUnsafe extends VertexWriterUnsafe<BlockVertex> {
|
|||
MemoryUtil.memPutByte(ptr + 30, RenderMath.nb(nZ));
|
||||
|
||||
ptr += 32;
|
||||
advance();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,5 @@ public class PosTexNormalWriterUnsafe extends VertexWriterUnsafe<PosTexNormalVer
|
|||
MemoryUtil.memPutByte(ptr + 22, RenderMath.nb(nZ));
|
||||
|
||||
ptr += 23;
|
||||
advance();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,8 +12,6 @@ public abstract class VertexWriterUnsafe<V extends VertexType> implements Vertex
|
|||
|
||||
public final V type;
|
||||
protected final ByteBuffer buffer;
|
||||
private int totalVertices;
|
||||
private int writeVertex;
|
||||
protected long ptr;
|
||||
|
||||
protected VertexWriterUnsafe(V type, ByteBuffer buffer) {
|
||||
|
@ -22,21 +20,14 @@ public abstract class VertexWriterUnsafe<V extends VertexType> implements Vertex
|
|||
this.ptr = MemoryUtil.memAddress(buffer);
|
||||
}
|
||||
|
||||
protected void advance() {
|
||||
writeVertex++;
|
||||
// account for seeking
|
||||
if (writeVertex > totalVertices) totalVertices = writeVertex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seekToVertex(int vertex) {
|
||||
buffer.position(type.byteOffset(vertex));
|
||||
writeVertex = vertex;
|
||||
public void seek(long offset) {
|
||||
buffer.position((int) offset);
|
||||
ptr = MemoryUtil.memAddress(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexList intoReader() {
|
||||
return type.createReader(buffer, totalVertices);
|
||||
public VertexList intoReader(int vertices) {
|
||||
return type.createReader(buffer, vertices);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,16 +9,13 @@ import net.minecraftforge.event.entity.EntityLeaveWorldEvent;
|
|||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
@Mod.EventBusSubscriber(Dist.CLIENT)
|
||||
public class EntityWorldHandler {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onEntityJoinWorld(EntityJoinWorldEvent event) {
|
||||
if (event.getWorld().isClientSide && Backend.isOn()) InstancedRenderDispatcher.getEntities(event.getWorld())
|
||||
.queueAdd(event.getEntity());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onEntityLeaveWorld(EntityLeaveWorldEvent event) {
|
||||
if (event.getWorld().isClientSide && Backend.isOn()) InstancedRenderDispatcher.getEntities(event.getWorld())
|
||||
.remove(event.getEntity());
|
||||
|
|
|
@ -17,10 +17,8 @@ import net.minecraftforge.event.world.WorldEvent;
|
|||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
@Mod.EventBusSubscriber(Dist.CLIENT)
|
||||
public class ForgeEvents {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void addToDebugScreen(RenderGameOverlayEvent.Text event) {
|
||||
|
||||
if (Minecraft.getInstance().options.renderDebug) {
|
||||
|
@ -37,12 +35,10 @@ public class ForgeEvents {
|
|||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void unloadWorld(WorldEvent.Unload event) {
|
||||
WorldAttached.invalidateWorld(event.getWorld());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void tickLight(TickEvent.ClientTickEvent e) {
|
||||
if (e.phase == TickEvent.Phase.END && Backend.isGameActive()) {
|
||||
LightUpdater.get(Minecraft.getInstance().level)
|
||||
|
|
|
@ -16,7 +16,7 @@ public interface ClientLevelExtension {
|
|||
*/
|
||||
Iterable<Entity> flywheel$getAllLoadedEntities();
|
||||
|
||||
static ClientLevelExtension cast(ClientLevel level) {
|
||||
return (ClientLevelExtension) level;
|
||||
static Iterable<Entity> getAllLoadedEntities(ClientLevel level) {
|
||||
return ((ClientLevelExtension) level).flywheel$getAllLoadedEntities();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
package com.jozufozu.flywheel.vanilla;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.InstancerManager;
|
||||
import com.jozufozu.flywheel.api.instance.DynamicInstance;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
|
@ -10,7 +14,7 @@ import com.jozufozu.flywheel.core.BasicModelSupplier;
|
|||
import com.jozufozu.flywheel.core.hardcoded.ModelPart;
|
||||
import com.jozufozu.flywheel.core.material.MaterialShaders;
|
||||
import com.jozufozu.flywheel.core.structs.StructTypes;
|
||||
import com.jozufozu.flywheel.core.structs.oriented.OrientedData;
|
||||
import com.jozufozu.flywheel.core.structs.oriented.OrientedPart;
|
||||
import com.jozufozu.flywheel.util.AnimationTickHolder;
|
||||
import com.mojang.math.Quaternion;
|
||||
import com.mojang.math.Vector3f;
|
||||
|
@ -24,7 +28,7 @@ public class BellInstance extends BlockEntityInstance<BellBlockEntity> implement
|
|||
|
||||
private static final BasicModelSupplier MODEL = new BasicModelSupplier(BellInstance::createBellModel, new Material(Sheets.solidBlockSheet(), MaterialShaders.SHADED_VERTEX, MaterialShaders.DEFAULT_FRAGMENT));
|
||||
|
||||
private final OrientedData bell;
|
||||
private final OrientedPart bell;
|
||||
|
||||
private float lastRingTime = Float.NaN;
|
||||
|
||||
|
@ -59,12 +63,17 @@ public class BellInstance extends BlockEntityInstance<BellBlockEntity> implement
|
|||
relight(getWorldPosition(), bell);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCrumblingParts(List<InstancedPart> data) {
|
||||
Collections.addAll(data, bell);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
bell.delete();
|
||||
}
|
||||
|
||||
private OrientedData createBellInstance() {
|
||||
private OrientedPart createBellInstance() {
|
||||
return instancerManager.factory(StructTypes.ORIENTED)
|
||||
.model(MODEL)
|
||||
.createInstance();
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package com.jozufozu.flywheel.vanilla;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.InstancerManager;
|
||||
import com.jozufozu.flywheel.api.instance.DynamicInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
|
||||
|
@ -12,8 +15,8 @@ import com.jozufozu.flywheel.core.BasicModelSupplier;
|
|||
import com.jozufozu.flywheel.core.hardcoded.ModelPart;
|
||||
import com.jozufozu.flywheel.core.material.MaterialShaders;
|
||||
import com.jozufozu.flywheel.core.structs.StructTypes;
|
||||
import com.jozufozu.flywheel.core.structs.model.ModelData;
|
||||
import com.jozufozu.flywheel.core.structs.oriented.OrientedData;
|
||||
import com.jozufozu.flywheel.core.structs.model.TransformedPart;
|
||||
import com.jozufozu.flywheel.core.structs.oriented.OrientedPart;
|
||||
import com.jozufozu.flywheel.util.AnimationTickHolder;
|
||||
import com.mojang.math.Quaternion;
|
||||
import com.mojang.math.Vector3f;
|
||||
|
@ -37,8 +40,8 @@ public class ChestInstance<T extends BlockEntity & LidBlockEntity> extends Block
|
|||
private static final BiFunction<ChestType, Material, BasicModelSupplier> LID = Util.memoize((type, mat) -> new BasicModelSupplier(() -> createLidModel(type, mat.sprite()), new com.jozufozu.flywheel.api.material.Material(Sheets.chestSheet(), MaterialShaders.SHADED_VERTEX, MaterialShaders.DEFAULT_FRAGMENT)));
|
||||
private static final BiFunction<ChestType, Material, BasicModelSupplier> BASE = Util.memoize((type, mat) -> new BasicModelSupplier(() -> createBaseModel(type, mat.sprite()), new com.jozufozu.flywheel.api.material.Material(Sheets.chestSheet(), MaterialShaders.SHADED_VERTEX, MaterialShaders.DEFAULT_FRAGMENT)));
|
||||
|
||||
private final OrientedData body;
|
||||
private final ModelData lid;
|
||||
private final OrientedPart body;
|
||||
private final TransformedPart lid;
|
||||
|
||||
private final Float2FloatFunction lidProgress;
|
||||
private final Material renderMaterial;
|
||||
|
@ -108,22 +111,27 @@ public class ChestInstance<T extends BlockEntity & LidBlockEntity> extends Block
|
|||
relight(getWorldPosition(), body, lid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCrumblingParts(List<InstancedPart> data) {
|
||||
Collections.addAll(data, body, lid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
body.delete();
|
||||
lid.delete();
|
||||
}
|
||||
|
||||
private OrientedData baseInstance() {
|
||||
private OrientedPart baseInstance() {
|
||||
|
||||
return instancerManager.factory(StructTypes.ORIENTED)
|
||||
.model(BASE.apply(chestType, renderMaterial))
|
||||
.createInstance();
|
||||
}
|
||||
|
||||
private ModelData lidInstance() {
|
||||
private TransformedPart lidInstance() {
|
||||
|
||||
return instancerManager.factory(StructTypes.MODEL)
|
||||
return instancerManager.factory(StructTypes.TRANSFORMED)
|
||||
.model(LID.apply(chestType, renderMaterial))
|
||||
.createInstance();
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import com.jozufozu.flywheel.core.hardcoded.ModelPart;
|
|||
import com.jozufozu.flywheel.core.material.MaterialShaders;
|
||||
import com.jozufozu.flywheel.core.model.Mesh;
|
||||
import com.jozufozu.flywheel.core.structs.StructTypes;
|
||||
import com.jozufozu.flywheel.core.structs.model.ModelData;
|
||||
import com.jozufozu.flywheel.core.structs.model.TransformedPart;
|
||||
import com.jozufozu.flywheel.util.AnimationTickHolder;
|
||||
import com.jozufozu.flywheel.util.transform.TransformStack;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
@ -35,8 +35,8 @@ public class MinecartInstance<T extends AbstractMinecart> extends EntityInstance
|
|||
|
||||
private final PoseStack stack = new PoseStack();
|
||||
|
||||
private final ModelData body;
|
||||
private ModelData contents;
|
||||
private final TransformedPart body;
|
||||
private TransformedPart contents;
|
||||
private BlockState blockState;
|
||||
private boolean active;
|
||||
|
||||
|
@ -48,6 +48,11 @@ public class MinecartInstance<T extends AbstractMinecart> extends EntityInstance
|
|||
contents = getContents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean decreaseFramerateWithDistance() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
BlockState displayBlockState = entity.getDisplayBlockState();
|
||||
|
@ -153,7 +158,7 @@ public class MinecartInstance<T extends AbstractMinecart> extends EntityInstance
|
|||
if (contents != null) contents.delete();
|
||||
}
|
||||
|
||||
private ModelData getContents() {
|
||||
private TransformedPart getContents() {
|
||||
RenderShape shape = blockState.getRenderShape();
|
||||
|
||||
if (shape == RenderShape.ENTITYBLOCK_ANIMATED) {
|
||||
|
@ -166,13 +171,13 @@ public class MinecartInstance<T extends AbstractMinecart> extends EntityInstance
|
|||
if (shape == RenderShape.INVISIBLE)
|
||||
return null;
|
||||
|
||||
return instancerManager.factory(StructTypes.MODEL)
|
||||
return instancerManager.factory(StructTypes.TRANSFORMED)
|
||||
.model(Models.block(blockState))
|
||||
.createInstance();
|
||||
}
|
||||
|
||||
private ModelData getBody() {
|
||||
return instancerManager.factory(StructTypes.MODEL)
|
||||
private TransformedPart getBody() {
|
||||
return instancerManager.factory(StructTypes.TRANSFORMED)
|
||||
.model(MODEL)
|
||||
.createInstance();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package com.jozufozu.flywheel.vanilla;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.InstancerManager;
|
||||
import com.jozufozu.flywheel.api.instance.DynamicInstance;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
|
@ -10,7 +13,7 @@ import com.jozufozu.flywheel.core.BasicModelSupplier;
|
|||
import com.jozufozu.flywheel.core.hardcoded.ModelPart;
|
||||
import com.jozufozu.flywheel.core.material.MaterialShaders;
|
||||
import com.jozufozu.flywheel.core.structs.StructTypes;
|
||||
import com.jozufozu.flywheel.core.structs.model.ModelData;
|
||||
import com.jozufozu.flywheel.core.structs.model.TransformedPart;
|
||||
import com.jozufozu.flywheel.util.AnimationTickHolder;
|
||||
import com.jozufozu.flywheel.util.transform.TransformStack;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
@ -33,8 +36,8 @@ public class ShulkerBoxInstance extends BlockEntityInstance<ShulkerBoxBlockEntit
|
|||
|
||||
private final TextureAtlasSprite texture;
|
||||
|
||||
private final ModelData base;
|
||||
private final ModelData lid;
|
||||
private final TransformedPart base;
|
||||
private final TransformedPart lid;
|
||||
private final PoseStack stack = new PoseStack();
|
||||
|
||||
private float lastProgress = Float.NaN;
|
||||
|
@ -87,6 +90,11 @@ public class ShulkerBoxInstance extends BlockEntityInstance<ShulkerBoxBlockEntit
|
|||
stack.popPose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCrumblingParts(List<InstancedPart> data) {
|
||||
Collections.addAll(data, base, lid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
base.delete();
|
||||
|
@ -98,14 +106,14 @@ public class ShulkerBoxInstance extends BlockEntityInstance<ShulkerBoxBlockEntit
|
|||
relight(pos, base, lid);
|
||||
}
|
||||
|
||||
private ModelData makeBaseInstance() {
|
||||
return instancerManager.factory(StructTypes.MODEL)
|
||||
private TransformedPart makeBaseInstance() {
|
||||
return instancerManager.factory(StructTypes.TRANSFORMED)
|
||||
.model(BASE.apply(texture))
|
||||
.createInstance();
|
||||
}
|
||||
|
||||
private ModelData makeLidInstance() {
|
||||
return instancerManager.factory(StructTypes.MODEL)
|
||||
private TransformedPart makeLidInstance() {
|
||||
return instancerManager.factory(StructTypes.TRANSFORMED)
|
||||
.model(LID.apply(texture))
|
||||
.createInstance();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue