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