diff --git a/src/main/java/com/jozufozu/flywheel/Flywheel.java b/src/main/java/com/jozufozu/flywheel/Flywheel.java index 7f0ff40a7..08fd9766c 100644 --- a/src/main/java/com/jozufozu/flywheel/Flywheel.java +++ b/src/main/java/com/jozufozu/flywheel/Flywheel.java @@ -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.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); diff --git a/src/main/java/com/jozufozu/flywheel/api/InstanceData.java b/src/main/java/com/jozufozu/flywheel/api/InstancedPart.java similarity index 65% rename from src/main/java/com/jozufozu/flywheel/api/InstanceData.java rename to src/main/java/com/jozufozu/flywheel/api/InstancedPart.java index a3471e0f7..5f42a9499 100644 --- a/src/main/java/com/jozufozu/flywheel/api/InstanceData.java +++ b/src/main/java/com/jozufozu/flywheel/api/InstancedPart.java @@ -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(); } diff --git a/src/main/java/com/jozufozu/flywheel/api/Instancer.java b/src/main/java/com/jozufozu/flywheel/api/Instancer.java index 5b6ac1cb4..7a0bc0798 100644 --- a/src/main/java/com/jozufozu/flywheel/api/Instancer.java +++ b/src/main/java/com/jozufozu/flywheel/api/Instancer.java @@ -18,7 +18,7 @@ package com.jozufozu.flywheel.api; * * @param the data that represents a copy of the instanced model. */ -public interface Instancer { +public interface Instancer { /** * @return a handle to a new copy of this model. */ diff --git a/src/main/java/com/jozufozu/flywheel/api/InstancerFactory.java b/src/main/java/com/jozufozu/flywheel/api/InstancerFactory.java index 102c96c56..7efb7e4e1 100644 --- a/src/main/java/com/jozufozu/flywheel/api/InstancerFactory.java +++ b/src/main/java/com/jozufozu/flywheel/api/InstancerFactory.java @@ -2,7 +2,7 @@ package com.jozufozu.flywheel.api; import com.jozufozu.flywheel.core.model.ModelSupplier; -public interface InstancerFactory { +public interface InstancerFactory { /** * Get an instancer for the given model. Calling this method twice with the same key will return the same instancer. diff --git a/src/main/java/com/jozufozu/flywheel/api/InstancerManager.java b/src/main/java/com/jozufozu/flywheel/api/InstancerManager.java index 73cda7b3d..0b174a397 100644 --- a/src/main/java/com/jozufozu/flywheel/api/InstancerManager.java +++ b/src/main/java/com/jozufozu/flywheel/api/InstancerManager.java @@ -6,7 +6,7 @@ import net.minecraft.core.Vec3i; public interface InstancerManager { - InstancerFactory factory(StructType type); + InstancerFactory factory(StructType type); Vec3i getOriginCoordinate(); diff --git a/src/main/java/com/jozufozu/flywheel/api/MaterialGroup.java b/src/main/java/com/jozufozu/flywheel/api/MaterialGroup.java index e8329c4bf..380e6f892 100644 --- a/src/main/java/com/jozufozu/flywheel/api/MaterialGroup.java +++ b/src/main/java/com/jozufozu/flywheel/api/MaterialGroup.java @@ -11,5 +11,5 @@ public interface MaterialGroup { * @param The type representing the per instance data. * @return A material you can use to render models. */ - InstancerFactory material(StructType spec); + InstancerFactory material(StructType spec); } diff --git a/src/main/java/com/jozufozu/flywheel/api/instance/DynamicInstance.java b/src/main/java/com/jozufozu/flywheel/api/instance/DynamicInstance.java index 86e43e77b..63668c034 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instance/DynamicInstance.java +++ b/src/main/java/com/jozufozu/flywheel/api/instance/DynamicInstance.java @@ -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 { *
* DISPATCHED IN PARALLEL, don't attempt to mutate anything outside this instance. *
- * {@link Instancer}/{@link InstanceData} creation/acquisition is safe here. + * {@link Instancer}/{@link InstancedPart} creation/acquisition is safe here. */ void beginFrame(); diff --git a/src/main/java/com/jozufozu/flywheel/api/instance/TickableInstance.java b/src/main/java/com/jozufozu/flywheel/api/instance/TickableInstance.java index 488ba8697..8a91965cd 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instance/TickableInstance.java +++ b/src/main/java/com/jozufozu/flywheel/api/instance/TickableInstance.java @@ -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 { *
* DISPATCHED IN PARALLEL, don't attempt to mutate anything outside of this instance. *
- * {@link Instancer}/{@link InstanceData} creation/acquisition is safe here. + * {@link Instancer}/{@link InstancedPart} creation/acquisition is safe here. */ void tick(); diff --git a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexWriter.java b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexWriter.java index ea883815b..a16f0eec5 100644 --- a/src/main/java/com/jozufozu/flywheel/api/vertex/VertexWriter.java +++ b/src/main/java/com/jozufozu/flywheel/api/vertex/VertexWriter.java @@ -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++) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/RenderWork.java b/src/main/java/com/jozufozu/flywheel/backend/RenderWork.java index c47db732c..48b5061ef 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/RenderWork.java +++ b/src/main/java/com/jozufozu/flywheel/backend/RenderWork.java @@ -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 runs = new ConcurrentLinkedQueue<>(); - @SubscribeEvent(priority = EventPriority.LOWEST) public static void onRenderWorldLast(RenderLevelLastEvent event) { while (!runs.isEmpty()) { runs.remove() diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/GlFence.java b/src/main/java/com/jozufozu/flywheel/backend/gl/GlFence.java index 78f6df423..f2b8c75c0 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/GlFence.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/GlFence.java @@ -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); - } - - glDeleteSync(fence); + poll0(); } + 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; } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/GlStateTracker.java b/src/main/java/com/jozufozu/flywheel/backend/gl/GlStateTracker.java index a352e9465..500537425 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/GlStateTracker.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/GlStateTracker.java @@ -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]); + } } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/GlVertexArray.java b/src/main/java/com/jozufozu/flywheel/backend/gl/GlVertexArray.java index 7de9ef863..b0540f66f 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/GlVertexArray.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/GlVertexArray.java @@ -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; + } + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java index 09c186a9d..395c514ec 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/GlBuffer.java @@ -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); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java index bf9293be6..e0ffa6c26 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/PersistentGlBuffer.java @@ -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; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java index e12af1e4a..e39e3bb0d 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/AbstractInstancer.java @@ -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 implements Instancer { +public abstract class AbstractInstancer implements Instancer { - protected final Supplier factory; + protected final StructType type; protected final ArrayList data = new ArrayList<>(); protected boolean anyToRemove; - protected AbstractInstancer(Supplier factory) { - this.factory = factory; + protected AbstractInstancer(StructType type) { + this.type = type; } /** @@ -23,7 +23,7 @@ public abstract class AbstractInstancer implements Insta */ @Override public D createInstance() { - return _add(factory.get()); + return _add(type.create()); } /** diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java index fab880b22..82addca0c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java @@ -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); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java index f2ccf13de..edb4ea4bd 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java @@ -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 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) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterialGroup.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterialGroup.java index 618d53d45..77b48809d 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterialGroup.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchedMaterialGroup.java @@ -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, CPUInstancerFactory> materials = new HashMap<>(); + private final Map, CPUInstancerFactory> materials = new HashMap<>(); private int vertexCount; private int instanceCount; @@ -26,7 +26,7 @@ public class BatchedMaterialGroup implements MaterialGroup { @SuppressWarnings("unchecked") @Override - public CPUInstancerFactory material(StructType type) { + public CPUInstancerFactory material(StructType type) { return (CPUInstancerFactory) materials.computeIfAbsent(type, CPUInstancerFactory::new); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java index 75a860a49..d5044f97c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/BatchingEngine.java @@ -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, CPUInstancerFactory> factories = new HashMap<>(); + private final Map, CPUInstancerFactory> factories = new HashMap<>(); private final BatchDrawingTracker batchTracker = new BatchDrawingTracker(); @SuppressWarnings("unchecked") @Override - public CPUInstancerFactory factory(StructType type) { + public CPUInstancerFactory factory(StructType type) { return (CPUInstancerFactory) factories.computeIfAbsent(type, CPUInstancerFactory::new); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java index 5e26617ca..d03d5ffce 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancer.java @@ -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 extends AbstractInstancer { +public class CPUInstancer extends AbstractInstancer { // private final Batched batchingType; // // final ModelTransformer sbb; public CPUInstancer(StructType type) { - super(type::create); + super(type); // batchingType = type; // // sbb = new ModelTransformer(modelData.get()); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancerFactory.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancerFactory.java index c2dc7183b..11965c7da 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancerFactory.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/batching/CPUInstancerFactory.java @@ -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 implements InstancerFactory { +public class CPUInstancerFactory implements InstancerFactory { protected final Map> models; private final StructType type; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java index 6f9f12ea8..1ca88861b 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java @@ -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 extends Abstrac this.instancePos = pos.subtract(instancerManager.getOriginCoordinate()); } + public List getCrumblingParts() { + var out = new ArrayList(); + addCrumblingParts(out); + return out; + } + + public void addCrumblingParts(List 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 extends Abstrac return pos; } - protected InstancerFactory getTransformFactory() { - return instancerManager.factory(StructTypes.MODEL); + protected InstancerFactory getTransformFactory() { + return instancerManager.factory(StructTypes.TRANSFORMED); } - protected InstancerFactory getOrientedFactory() { + protected InstancerFactory getOrientedFactory() { return instancerManager.factory(StructTypes.ORIENTED); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstanceManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstanceManager.java index b20986db0..1265669ce 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstanceManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstanceManager.java @@ -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 { + private final Long2ObjectMap> posLookup = new Long2ObjectOpenHashMap<>(); + public BlockEntityInstanceManager(InstancerManager instancerManager) { super(instancerManager); } + public void getCrumblingInstances(long pos, List> 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 { @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 diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java index 368d1de36..6623b391c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancer.java @@ -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 extends AbstractInstancer { +public class GPUInstancer extends AbstractInstancer { - final BufferLayout instanceFormat; - final StructType instancedType; + public final BufferLayout instanceFormat; + public final StructType structType; + public final InstancedModel parent; GlBuffer vbo; int attributeBaseIndex; @@ -25,10 +27,11 @@ public class GPUInstancer extends AbstractInstancer { boolean anyToUpdate; - public GPUInstancer(StructType type) { - super(type::create); + public GPUInstancer(InstancedModel parent, StructType type) { + super(type); + this.parent = parent; this.instanceFormat = type.getLayout(); - instancedType = type; + this.structType = type; } @Override @@ -39,7 +42,7 @@ public class GPUInstancer extends AbstractInstancer { 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 extends AbstractInstancer { if (size > 0) { - final StructWriter writer = instancedType.getWriter(buf.unwrap()); + final StructWriter writer = structType.getWriter(buf.unwrap()); boolean sequential = true; for (int i = 0; i < size; i++) { @@ -115,7 +118,7 @@ public class GPUInstancer extends AbstractInstancer { } 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); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancerFactory.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancerFactory.java index 99b4b530e..4fd6f265c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancerFactory.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/GPUInstancerFactory.java @@ -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 */ -public class GPUInstancerFactory implements InstancerFactory { +public class GPUInstancerFactory implements InstancerFactory { protected final Map> models = new HashMap<>(); protected final StructType type; protected final List> uninitialized = new ArrayList<>(); - // FIXME: these should not be public - public final Multimap materials = HashMultimap.create(); - public final Multimap renderables = ArrayListMultimap.create(); + private final ListMultimap renderLists = ArrayListMultimap.create(); public GPUInstancerFactory(StructType type) { this.type = type; @@ -39,7 +37,7 @@ public class GPUInstancerFactory implements InstancerFac @Override public Instancer 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 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 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 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 layersToProcess) { + layersToProcess.addAll(renderLists.keySet()); + } + + public List getRenderList(RenderType type) { + var out = renderLists.get(type); + out.removeIf(Renderable::shouldRemove); + return out; + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedModel.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedModel.java index 18ef8a641..50b5e4015 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedModel.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancedModel.java @@ -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 { +public class InstancedModel { - final GPUInstancer instancer; - final ModelSupplier model; - private Map layers; + public final GPUInstancer instancer; + public final ModelSupplier model; + private List layers; - public InstancedModel(GPUInstancer instancer, ModelSupplier model) { - this.instancer = instancer; + public InstancedModel(StructType type, ModelSupplier model) { this.model = model; + this.instancer = new GPUInstancer<>(this, type); } - public Map init(MeshPool allocator) { + public void init() { instancer.init(); + buildLayers(); + } + + public List 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 { 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 { if (instancer.glInstanceCount > 0) { bufferedMesh.drawInstances(vao, instancer.glInstanceCount); } - - // persistent mapping sync point - instancer.vbo.doneForThisFrame(); } } @@ -72,6 +88,9 @@ public class InstancedModel { 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 { instancer.vbo.delete(); instancer.vbo = null; - for (var layer : layers.values()) { + for (var layer : layers) { layer.delete(); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java index f87307d36..ee34b31f7 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java @@ -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

implements Engine { @@ -41,11 +62,10 @@ public class InstancingEngine

implements Engine { protected BlockPos originCoordinate = BlockPos.ZERO; protected final ProgramCompiler

context; - private MeshPool allocator; - protected final Map, GPUInstancerFactory> factories = new HashMap<>(); + protected final Map, GPUInstancerFactory> factories = new HashMap<>(); - protected final Set toRender = new HashSet<>(); + protected final Set layersToProcess = new HashSet<>(); private final WeakHashSet listeners; private int vertexCount; @@ -60,7 +80,7 @@ public class InstancingEngine

implements Engine { @SuppressWarnings("unchecked") @NotNull @Override - public GPUInstancerFactory factory(StructType type) { + public GPUInstancerFactory factory(StructType type) { return (GPUInstancerFactory) factories.computeIfAbsent(type, GPUInstancerFactory::new); } @@ -74,14 +94,18 @@ public class InstancingEngine

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,9 +114,7 @@ public class InstancingEngine

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()); - } + render(type, camX, camY, camZ, vp, context.level()); } protected void render(RenderType type, double camX, double camY, double camZ, Matrix4f viewProjection, ClientLevel level) { @@ -101,55 +123,36 @@ public class InstancingEngine

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); - - instanceCount += factory.getInstanceCount(); - vertexCount += factory.getVertexCount(); - - toRender.forEach(Renderable::render); - } + 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(); } 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

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

implements Engine { info.add("Origin: " + originCoordinate.getX() + ", " + originCoordinate.getY() + ", " + originCoordinate.getZ()); } - private MeshPool getModelAllocator() { - if (allocator == null) { - allocator = createAllocator(); + public void renderCrumbling(LevelRenderer levelRenderer, ClientLevel level, PoseStack stack, Camera camera, Matrix4f projectionMatrix) { + var dataByStage = getDataByStage(levelRenderer, level); + if (dataByStage.isEmpty()) { + return; + } + + var map = modelsToParts(dataByStage); + var stateSnapshot = GameStateRegistry.takeSnapshot(); + + 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(); + } } - return this.allocator; } - private static MeshPool createAllocator() { + @NotNull + private Map> modelsToParts(Int2ObjectMap>> dataByStage) { + var map = new HashMap>(); - // FIXME: Windows AMD Drivers don't like ..BaseVertex - return new MeshPool(Formats.POS_TEX_NORMAL); + 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>> 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>>(); + + for (var entry : destructionProgress.long2ObjectEntrySet()) { + SortedSet 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 diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/Renderable.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/Renderable.java index 4ac104a4d..68a7ae84a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/Renderable.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/Renderable.java @@ -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(); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/ElementBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/model/ElementBuffer.java index 8227ad019..0eb07f21d 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/model/ElementBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/model/ElementBuffer.java @@ -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(); - } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/model/MeshPool.java b/src/main/java/com/jozufozu/flywheel/backend/model/MeshPool.java index 8ea30abc4..2bf506606 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/model/MeshPool.java +++ b/src/main/java/com/jozufozu/flywheel/backend/model/MeshPool.java @@ -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 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 meshes = new HashMap<>(); + private final List allBuffered = new ArrayList<>(); private final List 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); - pendingUpload.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; + 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; + model.byteIndex = byteIndex; - vertices += model.mesh.getVertexCount(); + byteIndex += model.mesh.size(); } - this.vertices = vertices; + 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 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(); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/CoreShaderInfoMap.java b/src/main/java/com/jozufozu/flywheel/core/CoreShaderInfoMap.java index 25c187c4f..e69a856c5 100644 --- a/src/main/java/com/jozufozu/flywheel/core/CoreShaderInfoMap.java +++ b/src/main/java/com/jozufozu/flywheel/core/CoreShaderInfoMap.java @@ -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 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, diff --git a/src/main/java/com/jozufozu/flywheel/core/FullscreenQuad.java b/src/main/java/com/jozufozu/flywheel/core/FullscreenQuad.java index b5a34c28a..61f83a635 100644 --- a/src/main/java/com/jozufozu/flywheel/core/FullscreenQuad.java +++ b/src/main/java/com/jozufozu/flywheel/core/FullscreenQuad.java @@ -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,8 +50,8 @@ public class FullscreenQuad { vao.enableArrays(1); - vao.bindAttributes(vbo, 0, LAYOUT); - } + vao.bindAttributes(vbo, 0, LAYOUT, 0L); + } } public void draw() { diff --git a/src/main/java/com/jozufozu/flywheel/core/QuadConverter.java b/src/main/java/com/jozufozu/flywheel/core/QuadConverter.java index 537db4dd7..d55568b13 100644 --- a/src/main/java/com/jozufozu/flywheel/core/QuadConverter.java +++ b/src/main/java/com/jozufozu/flywheel/core/QuadConverter.java @@ -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(); diff --git a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java index d7be53423..06692e93b 100644 --- a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java +++ b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java @@ -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; @@ -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); - - toRender.forEach(Renderable::render); - } + if (toRender.isEmpty()) { + continue; } + + for (var renderable : toRender) { + + setup(instanceType, renderable.getMaterial(), coreShaderInfo, camX, camY, camZ, viewProjection, level, renderable.getVertexType()); + + renderable.render(); + } + } currentLayer.clearRenderState(); diff --git a/src/main/java/com/jozufozu/flywheel/core/hardcoded/ModelPart.java b/src/main/java/com/jozufozu/flywheel/core/hardcoded/ModelPart.java index 4d2f94202..a723692a8 100644 --- a/src/main/java/com/jozufozu/flywheel/core/hardcoded/ModelPart.java +++ b/src/main/java/com/jozufozu/flywheel/core/hardcoded/ModelPart.java @@ -34,7 +34,7 @@ public class ModelPart implements Mesh { cuboid.buffer(writer); } - reader = writer.intoReader(); + reader = writer.intoReader(this.vertices); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/instancing/ConditionalInstance.java b/src/main/java/com/jozufozu/flywheel/core/instancing/ConditionalInstance.java index cfd9d79b0..db420b2e9 100644 --- a/src/main/java/com/jozufozu/flywheel/core/instancing/ConditionalInstance.java +++ b/src/main/java/com/jozufozu/flywheel/core/instancing/ConditionalInstance.java @@ -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 { +public class ConditionalInstance { final Instancer model; ICondition condition; diff --git a/src/main/java/com/jozufozu/flywheel/core/instancing/GroupInstance.java b/src/main/java/com/jozufozu/flywheel/core/instancing/GroupInstance.java index a6c0a86c1..8ccdc143d 100644 --- a/src/main/java/com/jozufozu/flywheel/core/instancing/GroupInstance.java +++ b/src/main/java/com/jozufozu/flywheel/core/instancing/GroupInstance.java @@ -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 extends AbstractCollection { +public class GroupInstance extends AbstractCollection { final Instancer model; final List backing; @@ -48,14 +48,14 @@ public class GroupInstance extends AbstractCollection } } else { List 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 extends AbstractCollection @Override public void clear() { - backing.forEach(InstanceData::delete); + backing.forEach(InstancedPart::delete); backing.clear(); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/instancing/SelectInstance.java b/src/main/java/com/jozufozu/flywheel/core/instancing/SelectInstance.java index 423434f1e..81c6de015 100644 --- a/src/main/java/com/jozufozu/flywheel/core/instancing/SelectInstance.java +++ b/src/main/java/com/jozufozu/flywheel/core/instancing/SelectInstance.java @@ -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 { +public class SelectInstance { final List> models; diff --git a/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java b/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java index 18faef22c..10b13e8a8 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/Mesh.java @@ -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()); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/BasicData.java b/src/main/java/com/jozufozu/flywheel/core/structs/ColoredLitPart.java similarity index 64% rename from src/main/java/com/jozufozu/flywheel/core/structs/BasicData.java rename to src/main/java/com/jozufozu/flywheel/core/structs/ColoredLitPart.java index 73a13149a..db8936937 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/BasicData.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/ColoredLitPart.java @@ -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 { +public abstract class ColoredLitPart extends InstancedPart implements FlatLit { public byte blockLight; public byte skyLight; @@ -15,15 +16,19 @@ public abstract class BasicData extends InstanceData implements FlatLit 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> 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 extends UnsafeBufferWriter { +public abstract class ColoredLitWriterUnsafe extends UnsafeBufferWriter { - public BasicWriterUnsafe(StructType structType, ByteBuffer byteBuffer) { + public ColoredLitWriterUnsafe(StructType structType, ByteBuffer byteBuffer) { super(structType, byteBuffer); } diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/FlatLit.java b/src/main/java/com/jozufozu/flywheel/core/structs/FlatLit.java index 3446e1500..01fd710a7 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/FlatLit.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/FlatLit.java @@ -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. *

* This only covers flat lighting, smooth lighting is still TODO. * * @param The name of the class that implements this interface. */ -public interface FlatLit> { +public interface FlatLit> { /** * @param blockLight An integer in the range [0, 15] representing the * amount of block light this instance should receive. diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/InstanceShaders.java b/src/main/java/com/jozufozu/flywheel/core/structs/InstanceShaders.java index 84e45497a..0b253cfeb 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/InstanceShaders.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/InstanceShaders.java @@ -14,7 +14,7 @@ import net.minecraft.resources.ResourceLocation; public class InstanceShaders { public static final BiConsumer 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"); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/StructTypes.java b/src/main/java/com/jozufozu/flywheel/core/structs/StructTypes.java index 23364d214..a11cec5c9 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/StructTypes.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/StructTypes.java @@ -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 MODEL = new ModelType(); - public static final StructType ORIENTED = new OrientedType(); + public static final StructType TRANSFORMED = new TransformedType(); + public static final StructType ORIENTED = new OrientedType(); } diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/model/ModelData.java b/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedPart.java similarity index 63% rename from src/main/java/com/jozufozu/flywheel/core/structs/model/ModelData.java rename to src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedPart.java index fa364c901..865f5bccd 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/model/ModelData.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedPart.java @@ -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 { +public class TransformedPart extends ColoredLitPart implements Transform { 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 { * This will allow the gpu to quickly discard all geometry for this instance, effectively "turning it off". *

*/ - public ModelData setEmptyTransform() { + public TransformedPart setEmptyTransform() { markDirty(); this.model.load(EMPTY_MATRIX_4f); @@ -39,7 +44,7 @@ public class ModelData extends BasicData implements Transform { return this; } - public ModelData loadIdentity() { + public TransformedPart loadIdentity() { markDirty(); this.model.setIdentity(); @@ -48,7 +53,7 @@ public class ModelData extends BasicData implements Transform { } @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 { } @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 { } @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 { } @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; + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/model/ModelType.java b/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedType.java similarity index 71% rename from src/main/java/com/jozufozu/flywheel/core/structs/model/ModelType.java rename to src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedType.java index df0cf052f..bf1c3809a 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/model/ModelType.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedType.java @@ -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 { +public class TransformedType implements StructType { public static final BufferLayout FORMAT = BufferLayout.builder() .addItems(CommonItems.LIGHT, CommonItems.RGBA) @@ -18,8 +18,8 @@ public class ModelType implements StructType { .build(); @Override - public ModelData create() { - return new ModelData(); + public TransformedPart create() { + return new TransformedPart(); } @Override @@ -28,17 +28,17 @@ public class ModelType implements StructType { } @Override - public StructWriter getWriter(ByteBuffer backing) { - return new ModelWriterUnsafe(this, backing); + public StructWriter 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()); diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/model/ModelWriterUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedWriterUnsafe.java similarity index 58% rename from src/main/java/com/jozufozu/flywheel/core/structs/model/ModelWriterUnsafe.java rename to src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedWriterUnsafe.java index 26b12801a..8634e0db7 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/model/ModelWriterUnsafe.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedWriterUnsafe.java @@ -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 { +public class TransformedWriterUnsafe extends ColoredLitWriterUnsafe { - public ModelWriterUnsafe(StructType structType, ByteBuffer byteBuffer) { + public TransformedWriterUnsafe(StructType structType, ByteBuffer byteBuffer) { super(structType, byteBuffer); } @Override - protected void writeInternal(ModelData d) { + protected void writeInternal(TransformedPart d) { super.writeInternal(d); long ptr = writePointer + 6; diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedData.java b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedData.java deleted file mode 100644 index 15a9ebfd9..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedData.java +++ /dev/null @@ -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; - } - -} - diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedPart.java b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedPart.java new file mode 100644 index 000000000..5608a9c34 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedPart.java @@ -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; + } +} + diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java index 829ce0121..97b1a33fb 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java @@ -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 { +public class OrientedType implements StructType { public static final BufferLayout FORMAT = BufferLayout.builder() .addItems(CommonItems.LIGHT, CommonItems.RGBA) @@ -19,8 +19,8 @@ public class OrientedType implements StructType { .build(); @Override - public OrientedData create() { - return new OrientedData(); + public OrientedPart create() { + return new OrientedPart(); } @Override @@ -29,7 +29,7 @@ public class OrientedType implements StructType { } @Override - public StructWriter getWriter(ByteBuffer backing) { + public StructWriter getWriter(ByteBuffer backing) { return new OrientedWriterUnsafe(this, backing); } @@ -39,7 +39,7 @@ public class OrientedType implements StructType { } @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) diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedWriterUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedWriterUnsafe.java index 8f030f837..fb03c4d1e 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedWriterUnsafe.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedWriterUnsafe.java @@ -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 { - public OrientedWriterUnsafe(StructType structType, ByteBuffer byteBuffer) { +public class OrientedWriterUnsafe extends ColoredLitWriterUnsafe { + public OrientedWriterUnsafe(StructType structType, ByteBuffer byteBuffer) { super(structType, byteBuffer); } @Override - protected void writeInternal(OrientedData d) { + protected void writeInternal(OrientedPart d) { long ptr = writePointer; super.writeInternal(d); diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockWriterUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockWriterUnsafe.java index 044160349..b67149e18 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockWriterUnsafe.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockWriterUnsafe.java @@ -52,6 +52,5 @@ public class BlockWriterUnsafe extends VertexWriterUnsafe { MemoryUtil.memPutByte(ptr + 30, RenderMath.nb(nZ)); ptr += 32; - advance(); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalWriterUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalWriterUnsafe.java index 0eac537f3..8d2a3612a 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalWriterUnsafe.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalWriterUnsafe.java @@ -40,6 +40,5 @@ public class PosTexNormalWriterUnsafe extends VertexWriterUnsafe 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 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); } } diff --git a/src/main/java/com/jozufozu/flywheel/event/EntityWorldHandler.java b/src/main/java/com/jozufozu/flywheel/event/EntityWorldHandler.java index c68054208..6746fd963 100644 --- a/src/main/java/com/jozufozu/flywheel/event/EntityWorldHandler.java +++ b/src/main/java/com/jozufozu/flywheel/event/EntityWorldHandler.java @@ -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()); diff --git a/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java b/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java index 19ab783d8..e398b8698 100644 --- a/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java +++ b/src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java @@ -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) diff --git a/src/main/java/com/jozufozu/flywheel/util/ClientLevelExtension.java b/src/main/java/com/jozufozu/flywheel/util/ClientLevelExtension.java index c4bb29bba..197e24a27 100644 --- a/src/main/java/com/jozufozu/flywheel/util/ClientLevelExtension.java +++ b/src/main/java/com/jozufozu/flywheel/util/ClientLevelExtension.java @@ -16,7 +16,7 @@ public interface ClientLevelExtension { */ Iterable flywheel$getAllLoadedEntities(); - static ClientLevelExtension cast(ClientLevel level) { - return (ClientLevelExtension) level; + static Iterable getAllLoadedEntities(ClientLevel level) { + return ((ClientLevelExtension) level).flywheel$getAllLoadedEntities(); } } diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/BellInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/BellInstance.java index af93f13cc..e1746a006 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/BellInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/BellInstance.java @@ -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 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 implement relight(getWorldPosition(), bell); } + @Override + public void addCrumblingParts(List 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(); diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java index 22c4c9a9f..a03163ec2 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java @@ -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 extends Block private static final BiFunction 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 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 extends Block relight(getWorldPosition(), body, lid); } + @Override + public void addCrumblingParts(List 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(); } diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java index 13d47f072..7adb8713f 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java @@ -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 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 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 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 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(); } diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java index 665525183..3674ef0b6 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java @@ -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 data) { + Collections.addAll(data, base, lid); + } + @Override public void remove() { base.delete(); @@ -98,14 +106,14 @@ public class ShulkerBoxInstance extends BlockEntityInstance