From 4ec1f8eaf31f95a8b6b95d8dacc9c333debab93e Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Tue, 26 Jul 2022 19:12:18 -0700 Subject: [PATCH] Culling experiments - Cull updates based on the view frustum. - Instances check themselves against a FrustumIntersection object - Make GlProgram not abstract - Leave in small debug rendering experiment --- .../java/com/jozufozu/flywheel/Flywheel.java | 7 +- .../flywheel/api/instance/Instance.java | 10 + .../com/jozufozu/flywheel/backend/Loader.java | 6 +- .../flywheel/backend/gl/shader/GlProgram.java | 15 +- .../backend/instancing/InstanceManager.java | 31 +-- .../backend/instancing/InstanceWorld.java | 5 +- .../blockentity/BlockEntityInstance.java | 14 +- .../instancing/entity/EntityInstance.java | 8 + .../instancing/InstancingEngine.java | 6 +- .../jozufozu/flywheel/core/DebugRender.java | 104 ++++++++ .../jozufozu/flywheel/core/RenderContext.java | 56 ++-- .../flywheel/core/compile/DebugCompiler.java | 89 +++++++ .../core/compile/FragmentCompiler.java | 72 ----- .../core/compile/InstancedArraysCompiler.java | 248 ++++++++++++++++++ .../core/compile/ProgramCompiler.java | 88 ------- .../flywheel/core/compile/VertexCompiler.java | 99 ------- .../crumbling/CrumblingInstanceManager.java | 17 -- .../core/crumbling/CrumblingRenderer.java | 4 +- .../model/TransformedWriterUnsafe.java | 6 +- .../flywheel/core/uniform/ViewProvider.java | 4 +- .../flywheel/mixin/ClientLevelMixin.java | 2 +- .../flywheel/mixin/LevelRendererMixin.java | 4 +- .../flywheel/mixin/RenderTypeMixin.java | 2 +- .../flywheel/mixin/matrix/Matrix3fMixin.java | 10 +- .../flywheel/mixin/matrix/Matrix4fMixin.java | 14 +- .../java/com/jozufozu/flywheel/util/Lazy.java | 4 + .../{ => extension}/ClientLevelExtension.java | 2 +- .../util/extension/Matrix3fExtension.java | 16 ++ .../util/extension/Matrix4fExtension.java | 16 ++ .../MatrixExtension.java} | 8 +- .../{ => extension}/RenderTypeExtension.java | 2 +- .../util/joml/FrustumIntersection.java | 39 +++ .../flywheel/util/joml/Quaternionf.java | 9 + .../vanilla/effect/ExampleEffect.java | 6 + .../assets/flywheel/flywheel/debug/debug.frag | 5 + .../assets/flywheel/flywheel/debug/debug.vert | 7 + 36 files changed, 648 insertions(+), 387 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/core/DebugRender.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/DebugCompiler.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/InstancedArraysCompiler.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java delete mode 100644 src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingInstanceManager.java rename src/main/java/com/jozufozu/flywheel/util/{ => extension}/ClientLevelExtension.java (94%) create mode 100644 src/main/java/com/jozufozu/flywheel/util/extension/Matrix3fExtension.java create mode 100644 src/main/java/com/jozufozu/flywheel/util/extension/Matrix4fExtension.java rename src/main/java/com/jozufozu/flywheel/util/{MatrixWrite.java => extension/MatrixExtension.java} (70%) rename src/main/java/com/jozufozu/flywheel/util/{ => extension}/RenderTypeExtension.java (93%) create mode 100644 src/main/resources/assets/flywheel/flywheel/debug/debug.frag create mode 100644 src/main/resources/assets/flywheel/flywheel/debug/debug.vert diff --git a/src/main/java/com/jozufozu/flywheel/Flywheel.java b/src/main/java/com/jozufozu/flywheel/Flywheel.java index 7aaa6a7f6..afcffa837 100644 --- a/src/main/java/com/jozufozu/flywheel/Flywheel.java +++ b/src/main/java/com/jozufozu/flywheel/Flywheel.java @@ -12,15 +12,15 @@ import com.jozufozu.flywheel.config.BackendTypeArgument; import com.jozufozu.flywheel.config.FlwCommands; import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.core.Components; +import com.jozufozu.flywheel.core.DebugRender; import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.core.QuadConverter; import com.jozufozu.flywheel.core.StitchedSprite; -import com.jozufozu.flywheel.core.compile.ProgramCompiler; +import com.jozufozu.flywheel.core.compile.InstancedArraysCompiler; import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer; import com.jozufozu.flywheel.core.model.Models; import com.jozufozu.flywheel.event.EntityWorldHandler; import com.jozufozu.flywheel.event.ForgeEvents; -import com.jozufozu.flywheel.event.ReloadRenderersEvent; import com.jozufozu.flywheel.mixin.PausedPartialTickAccessor; import com.jozufozu.flywheel.vanilla.VanillaInstances; import com.mojang.logging.LogUtils; @@ -80,7 +80,7 @@ public class Flywheel { forgeEventBus.addListener(FlwCommands::registerClientCommands); forgeEventBus.addListener(EventPriority.HIGHEST, QuadConverter::onRendererReload); - forgeEventBus.addListener(ProgramCompiler::invalidateAll); + forgeEventBus.addListener(InstancedArraysCompiler::invalidateAll); forgeEventBus.addListener(Models::onReload); forgeEventBus.addListener(MeshPool::reset); forgeEventBus.addListener(CrumblingRenderer::onReloadRenderers); @@ -108,6 +108,7 @@ public class Flywheel { // forgeEventBus.addListener(ExampleEffect::onReload); Components.init(); + DebugRender.init(); VanillaInstances.init(); diff --git a/src/main/java/com/jozufozu/flywheel/api/instance/Instance.java b/src/main/java/com/jozufozu/flywheel/api/instance/Instance.java index 6cc6e89d8..c52837e45 100644 --- a/src/main/java/com/jozufozu/flywheel/api/instance/Instance.java +++ b/src/main/java/com/jozufozu/flywheel/api/instance/Instance.java @@ -1,9 +1,19 @@ package com.jozufozu.flywheel.api.instance; +import com.jozufozu.flywheel.util.joml.FrustumIntersection; + import net.minecraft.core.BlockPos; public interface Instance { BlockPos getWorldPosition(); + /** + * Check this instance against a frustum.

+ * An implementor may choose to return a constant to skip the frustum check. + * @param frustum A frustum intersection tester for the current frame. + * @return {@code true} if this instance should be considered for updates. + */ + boolean checkFrustum(FrustumIntersection frustum); + boolean isRemoved(); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/Loader.java b/src/main/java/com/jozufozu/flywheel/backend/Loader.java index 3519ace3e..dfef2748b 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Loader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Loader.java @@ -6,7 +6,7 @@ import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.core.ComponentRegistry; import com.jozufozu.flywheel.core.compile.ContextShader; -import com.jozufozu.flywheel.core.compile.ProgramCompiler; +import com.jozufozu.flywheel.core.compile.InstancedArraysCompiler; import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer; import com.jozufozu.flywheel.core.source.FileResolution; import com.jozufozu.flywheel.core.source.ShaderLoadingException; @@ -70,8 +70,8 @@ public class Loader implements ResourceManagerReloadListener { for (StructType structType : ComponentRegistry.structTypes) { for (VertexType vertexType : ComponentRegistry.vertexTypes) { for (ContextShader contextShader : ComponentRegistry.contextShaders) { - var ctx = new ProgramCompiler.Context(vertexType, material, structType.getInstanceShader(), contextShader); - ProgramCompiler.INSTANCE.getProgram(ctx); + var ctx = new InstancedArraysCompiler.Context(vertexType, material, structType.getInstanceShader(), contextShader); + InstancedArraysCompiler.INSTANCE.getProgram(ctx); } } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlProgram.java b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlProgram.java index 84650d9b2..ea80d4cf5 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlProgram.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlProgram.java @@ -5,25 +5,19 @@ import static org.lwjgl.opengl.GL20.glGetUniformLocation; import static org.lwjgl.opengl.GL20.glUniform1i; import static org.lwjgl.opengl.GL20.glUniformMatrix4fv; -import java.nio.FloatBuffer; - import org.jetbrains.annotations.NotNull; -import org.lwjgl.system.MemoryStack; import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GlObject; import com.mojang.blaze3d.shaders.ProgramManager; -import com.mojang.math.Matrix4f; import net.minecraft.resources.ResourceLocation; -public abstract class GlProgram extends GlObject { - private static final FloatBuffer floatBuffer = MemoryStack.stackGet() - .mallocFloat(16); +public class GlProgram extends GlObject { public final ResourceLocation name; - protected GlProgram(ResourceLocation name, int handle) { + public GlProgram(ResourceLocation name, int handle) { this.name = name; setHandle(handle); } @@ -70,11 +64,6 @@ public abstract class GlProgram extends GlObject { return samplerUniform; } - protected static void uploadMatrixUniform(int uniform, Matrix4f mat) { - mat.store(floatBuffer); - glUniformMatrix4fv(uniform, false, floatBuffer); - } - @Override protected void deleteInternal(int handle) { glDeleteProgram(handle); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java index 297d9d0e9..319fb9607 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java @@ -15,9 +15,8 @@ import com.jozufozu.flywheel.backend.instancing.ratelimit.NonLimiter; import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.core.RenderContext; import com.jozufozu.flywheel.light.LightUpdater; -import com.mojang.math.Vector3f; +import com.jozufozu.flywheel.util.joml.FrustumIntersection; -import net.minecraft.client.Camera; import net.minecraft.core.BlockPos; public abstract class InstanceManager { @@ -100,27 +99,26 @@ public abstract class InstanceManager { int dY = pos.getY() - cY; int dZ = pos.getZ() - cZ; - if (tick.shouldUpdate(dX, dY, dZ)) instance.tick(); + if (!tick.shouldUpdate(dX, dY, dZ)) { + return; + } + + instance.tick(); } public void beginFrame(TaskEngine taskEngine, RenderContext context) { frame.tick(); processQueuedAdditions(); - Camera camera = context.camera(); - Vector3f look = camera.getLookVector(); - float lookX = look.x(); - float lookY = look.y(); - float lookZ = look.z(); - // integer camera pos - BlockPos cameraIntPos = camera.getBlockPosition(); + BlockPos cameraIntPos = context.camera().getBlockPosition(); int cX = cameraIntPos.getX(); int cY = cameraIntPos.getY(); int cZ = cameraIntPos.getZ(); + FrustumIntersection culler = context.culler(); var instances = getStorage().getInstancesForUpdate(); - distributeWork(taskEngine, instances, instance -> updateInstance(instance, lookX, lookY, lookZ, cX, cY, cZ)); + distributeWork(taskEngine, instances, instance -> updateInstance(instance, culler, cX, cY, cZ)); } private static void distributeWork(TaskEngine taskEngine, List instances, Consumer action) { @@ -140,7 +138,7 @@ public abstract class InstanceManager { } } - protected void updateInstance(DynamicInstance dyn, float lookX, float lookY, float lookZ, int cX, int cY, int cZ) { + protected void updateInstance(DynamicInstance dyn, FrustumIntersection test, int cX, int cY, int cZ) { if (!dyn.decreaseFramerateWithDistance()) { dyn.beginFrame(); return; @@ -151,15 +149,14 @@ public abstract class InstanceManager { int dY = worldPos.getY() - cY; int dZ = worldPos.getZ() - cZ; - // is it more than 2 blocks behind the camera? - int dist = 2; - float dot = (dX + lookX * dist) * lookX + (dY + lookY * dist) * lookY + (dZ + lookZ * dist) * lookZ; - if (dot < 0) { + if (!frame.shouldUpdate(dX, dY, dZ)) { return; } - if (frame.shouldUpdate(dX, dY, dZ)) + if (dyn.checkFrustum(test)) { dyn.beginFrame(); + } + } public void add(T obj) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java index 3962d4d1a..ccc177125 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceWorld.java @@ -13,7 +13,7 @@ import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine; import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.RenderContext; import com.jozufozu.flywheel.event.BeginFrameEvent; -import com.jozufozu.flywheel.util.ClientLevelExtension; +import com.jozufozu.flywheel.util.extension.ClientLevelExtension; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; @@ -133,10 +133,7 @@ public class InstanceWorld { */ public void renderStage(RenderContext context, RenderStage stage) { taskEngine.syncPoint(); - context.pushPose(); - context.translateBack(context.camera().getPosition()); engine.renderStage(taskEngine, context, stage); - context.popPose(); } /** diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java index 39a53e444..a46ce4f7c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/blockentity/BlockEntityInstance.java @@ -14,6 +14,7 @@ import com.jozufozu.flywheel.core.structs.model.TransformedPart; import com.jozufozu.flywheel.core.structs.oriented.OrientedPart; import com.jozufozu.flywheel.util.box.GridAlignedBB; import com.jozufozu.flywheel.util.box.ImmutableBox; +import com.jozufozu.flywheel.util.joml.FrustumIntersection; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.entity.BlockEntity; @@ -90,16 +91,13 @@ public abstract class BlockEntityInstance extends Abstrac return pos; } - protected InstancerFactory getTransformFactory() { - return instancerManager.factory(StructTypes.TRANSFORMED); - } - - protected InstancerFactory getOrientedFactory() { - return instancerManager.factory(StructTypes.ORIENTED); - } - @Override public ImmutableBox getVolume() { return GridAlignedBB.from(pos); } + + @Override + public boolean checkFrustum(FrustumIntersection frustum) { + return frustum.testAab(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstance.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstance.java index 4e6926317..352aa832b 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstance.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstance.java @@ -8,6 +8,7 @@ import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceM import com.jozufozu.flywheel.light.LightListener; import com.jozufozu.flywheel.light.TickingLightListener; import com.jozufozu.flywheel.util.box.GridAlignedBB; +import com.jozufozu.flywheel.util.joml.FrustumIntersection; import com.mojang.math.Vector3f; import net.minecraft.core.BlockPos; @@ -96,4 +97,11 @@ public abstract class EntityInstance extends AbstractInstance public BlockPos getWorldPosition() { return entity.blockPosition(); } + + @Override + public boolean checkFrustum(FrustumIntersection frustum) { + AABB aabb = entity.getBoundingBox(); + return frustum.testAab((float) aabb.minX, (float) aabb.minY, (float) aabb.minZ, + (float) aabb.maxX, (float) aabb.maxY, (float) aabb.maxZ); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java index 43d1acd41..45c14e724 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java @@ -20,7 +20,7 @@ import com.jozufozu.flywheel.backend.instancing.InstanceManager; import com.jozufozu.flywheel.backend.instancing.TaskEngine; import com.jozufozu.flywheel.core.RenderContext; import com.jozufozu.flywheel.core.compile.ContextShader; -import com.jozufozu.flywheel.core.compile.ProgramCompiler; +import com.jozufozu.flywheel.core.compile.InstancedArraysCompiler; import com.jozufozu.flywheel.core.source.FileResolution; import com.jozufozu.flywheel.core.uniform.UniformBuffer; import com.jozufozu.flywheel.util.WeakHashSet; @@ -137,9 +137,9 @@ public class InstancingEngine implements Engine { .getInstanceShader(); Material material = desc.material(); - var ctx = new ProgramCompiler.Context(vertexType, material, instanceShader, context); + var ctx = new InstancedArraysCompiler.Context(vertexType, material, instanceShader, context); - ProgramCompiler.INSTANCE.getProgram(ctx) + InstancedArraysCompiler.INSTANCE.getProgram(ctx) .bind(); UniformBuffer.getInstance().sync(); } diff --git a/src/main/java/com/jozufozu/flywheel/core/DebugRender.java b/src/main/java/com/jozufozu/flywheel/core/DebugRender.java new file mode 100644 index 000000000..70a0c4d1c --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/DebugRender.java @@ -0,0 +1,104 @@ +package com.jozufozu.flywheel.core; + +import org.lwjgl.opengl.GL46; +import org.lwjgl.system.MemoryStack; + +import com.jozufozu.flywheel.Flywheel; +import com.jozufozu.flywheel.backend.gl.GlStateTracker; +import com.jozufozu.flywheel.backend.gl.shader.GlProgram; +import com.jozufozu.flywheel.core.compile.DebugCompiler; +import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.util.Lazy; +import com.jozufozu.flywheel.util.joml.FrustumIntersection; +import com.mojang.blaze3d.systems.RenderSystem; + +public class DebugRender { + + private static final Lazy SHADER = Lazy.of(() -> DebugCompiler.INSTANCE.get(new DebugCompiler.Context(Files.VERTEX, Files.FRAGMENT))); + + private static final Lazy FRUSTUM_VBO = Lazy.of(Frustum::new); + + public static void init() { + Files.init(); + } + + public static void updateFrustum(FrustumIntersection culler) { + FRUSTUM_VBO.get() + .upload(culler); + } + + public static void drawFrustum() { + if (!FRUSTUM_VBO.isInitialized()) { + return; + } + + RenderSystem.disableCull(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + + try (var ignored = GlStateTracker.getRestoreState()) { + SHADER.get() + .bind(); + FRUSTUM_VBO.get() + .draw(); + } + } + + public static class Files { + public static final FileResolution VERTEX = FileResolution.get(Flywheel.rl("debug/debug.vert")); + public static final FileResolution FRAGMENT = FileResolution.get(Flywheel.rl("debug/debug.frag")); + + public static void init() { + + } + } + + // FIXME: This never worked (and the thing it was meant to debug is already fixed), + // but it should be a quick turnaround + private static class Frustum { + private static final int[] indices = new int[]{ + 0, 2, 3, 0, 3, 1, + 2, 6, 7, 2, 7, 3, + 6, 4, 5, 6, 5, 7, + 4, 0, 1, 4, 1, 5, + 0, 4, 6, 0, 6, 2, + 1, 5, 7, 1, 7, 3, + }; + + private static final int elementCount = indices.length; + private static final int indicesSize = elementCount * 4; + private static final int verticesSize = 3 * 8 * 4; + private final int buffer; + private final int vao; + + public Frustum() { + // holy moly DSA is nice + buffer = GL46.glCreateBuffers(); + GL46.glNamedBufferStorage(buffer, verticesSize + indicesSize, GL46.GL_DYNAMIC_STORAGE_BIT); + GL46.glNamedBufferSubData(buffer, 0, indices); + + vao = GL46.glCreateVertexArrays(); + GL46.glEnableVertexArrayAttrib(vao, 0); + GL46.glVertexArrayElementBuffer(vao, buffer); + GL46.glVertexArrayVertexBuffer(vao, 0, buffer, indicesSize, 3 * 4); + GL46.glVertexArrayAttribFormat(vao, 0, 3, GL46.GL_FLOAT, false, 0); + } + + public void upload(FrustumIntersection culler) { + try (var stack = MemoryStack.stackPush()) { + var buf = stack.malloc(3 * 8 * 4); + + culler.bufferPlanes(buf); + + GL46.glNamedBufferSubData(buffer, indicesSize, buf); + } + } + + public void draw() { + GL46.glEnableVertexArrayAttrib(vao, 0); + GL46.glVertexArrayElementBuffer(vao, buffer); + GL46.glBindVertexArray(vao); + GL46.glDrawElements(GL46.GL_TRIANGLES, elementCount, GL46.GL_UNSIGNED_INT, 0); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/RenderContext.java b/src/main/java/com/jozufozu/flywheel/core/RenderContext.java index 6fd3effbb..121e2d93a 100644 --- a/src/main/java/com/jozufozu/flywheel/core/RenderContext.java +++ b/src/main/java/com/jozufozu/flywheel/core/RenderContext.java @@ -2,56 +2,19 @@ package com.jozufozu.flywheel.core; import org.jetbrains.annotations.NotNull; -import com.jozufozu.flywheel.util.transform.TransformStack; +import com.jozufozu.flywheel.util.extension.Matrix4fExtension; +import com.jozufozu.flywheel.util.joml.FrustumIntersection; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Matrix3f; import com.mojang.math.Matrix4f; -import com.mojang.math.Quaternion; import net.minecraft.client.Camera; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.RenderBuffers; +import net.minecraft.world.phys.Vec3; public record RenderContext(LevelRenderer renderer, ClientLevel level, PoseStack stack, Matrix4f viewProjection, - Matrix4f projection, RenderBuffers buffers, Camera camera) implements TransformStack { - - @Override - public TransformStack multiply(Quaternion quaternion) { - return TransformStack.cast(stack).multiply(quaternion); - } - - @Override - public TransformStack scale(float factorX, float factorY, float factorZ) { - return TransformStack.cast(stack).scale(factorX, factorY, factorZ); - } - - @Override - public TransformStack pushPose() { - stack.pushPose(); - return TransformStack.cast(stack); - } - - @Override - public TransformStack popPose() { - stack.popPose(); - return TransformStack.cast(stack); - } - - @Override - public TransformStack mulPose(Matrix4f pose) { - return TransformStack.cast(stack).mulPose(pose); - } - - @Override - public TransformStack mulNormal(Matrix3f normal) { - return TransformStack.cast(stack).mulNormal(normal); - } - - @Override - public TransformStack translate(double x, double y, double z) { - return TransformStack.cast(stack).translate(x, y, z); - } + Matrix4f projection, RenderBuffers buffers, Camera camera, FrustumIntersection culler) { @NotNull public static Matrix4f createViewProjection(PoseStack view, Matrix4f projection) { @@ -59,4 +22,15 @@ public record RenderContext(LevelRenderer renderer, ClientLevel level, PoseStack viewProjection.multiply(view.last().pose()); return viewProjection; } + + public static FrustumIntersection createCuller(Camera camera, Matrix4f viewProjection) { + com.jozufozu.flywheel.util.joml.Matrix4f proj = Matrix4fExtension.clone(viewProjection); + + Vec3 cam = camera + .getPosition(); + + proj.translate((float) -cam.x, (float) -cam.y, (float) -cam.z); + + return new FrustumIntersection(proj); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/DebugCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/DebugCompiler.java new file mode 100644 index 000000000..319d2dc11 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/compile/DebugCompiler.java @@ -0,0 +1,89 @@ +package com.jozufozu.flywheel.core.compile; + +import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.backend.gl.GLSLVersion; +import com.jozufozu.flywheel.backend.gl.shader.GlProgram; +import com.jozufozu.flywheel.backend.gl.shader.GlShader; +import com.jozufozu.flywheel.backend.gl.shader.ShaderType; +import com.jozufozu.flywheel.core.source.CompilationContext; +import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.event.ReloadRenderersEvent; + +/** + * Simple shader compiler that pulls no excessive tricks.

+ * Useful for writing experimental shaders or + */ +public class DebugCompiler extends Memoizer { + + public static final DebugCompiler INSTANCE = new DebugCompiler(); + + private final ShaderCompiler shaderCompiler; + + private DebugCompiler() { + this.shaderCompiler = new ShaderCompiler(); + } + + @Override + public void invalidate() { + super.invalidate(); + shaderCompiler.invalidate(); + } + + @Override + protected GlProgram _create(DebugCompiler.Context ctx) { + + return new ProgramAssembler(ctx.vertex.getFileLoc()) + .attachShader(shaderCompiler.vertex(ctx.vertex)) + .attachShader(shaderCompiler.fragment(ctx.fragment)) + .link() + .build(GlProgram::new); + } + + @Override + protected void _destroy(GlProgram value) { + value.delete(); + } + + public static void invalidateAll(ReloadRenderersEvent ignored) { + INSTANCE.invalidate(); + } + + public record Context(FileResolution vertex, FileResolution fragment) { + } + + /** + * Handles compilation and deletion of vertex shaders. + */ + private static class ShaderCompiler extends Memoizer { + + public GlShader vertex(FileResolution source) { + return get(new Context(source, ShaderType.VERTEX)); + } + + public GlShader fragment(FileResolution source) { + return get(new Context(source, ShaderType.FRAGMENT)); + } + + @Override + protected GlShader _create(Context ctx) { + var index = new CompilationContext(); + + String source = CompileUtil.generateHeader(GLSLVersion.V420, ctx.type) + ctx.source.getFile() + .generateFinalSource(index); + + try { + return new GlShader(source, ctx.type, ImmutableList.of(ctx.source.getFileLoc())); + } catch (ShaderCompilationException e) { + throw e.withErrorLog(index); + } + } + + @Override + protected void _destroy(GlShader value) { + value.delete(); + } + + public record Context(FileResolution source, ShaderType type) { + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java deleted file mode 100644 index 2923de834..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/compile/FragmentCompiler.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.jozufozu.flywheel.core.compile; - -import com.google.common.collect.ImmutableList; -import com.jozufozu.flywheel.backend.gl.GLSLVersion; -import com.jozufozu.flywheel.backend.gl.shader.GlShader; -import com.jozufozu.flywheel.backend.gl.shader.ShaderType; -import com.jozufozu.flywheel.core.source.CompilationContext; -import com.jozufozu.flywheel.core.source.SourceFile; - -/** - * Handles compilation and deletion of fragment shaders. - */ -public class FragmentCompiler extends Memoizer { - - public FragmentCompiler() { - } - - @Override - protected GlShader _create(Context key) { - StringBuilder finalSource = new StringBuilder(); - - finalSource.append(CompileUtil.generateHeader(GLSLVersion.V420, ShaderType.FRAGMENT)); - - var ctx = new CompilationContext(); - - // MATERIAL - - SourceFile materialShader = key.materialShader; - finalSource.append(materialShader.generateFinalSource(ctx)); - - // CONTEXT - - SourceFile contextShaderSource = key.contextShader; - finalSource.append(contextShaderSource.generateFinalSource(ctx)); - - // MAIN - - finalSource.append(generateFooter()); - - try { - return new GlShader(finalSource.toString(), ShaderType.FRAGMENT, ImmutableList.of(materialShader.name, contextShaderSource.name)); - } catch (ShaderCompilationException e) { - throw e.withErrorLog(ctx); - } - } - - protected String generateFooter() { - return """ - void main() { - flw_initFragment(); - - flw_materialFragment(); - - flw_contextFragment(); - } - """; - } - - @Override - protected void _destroy(GlShader value) { - value.delete(); - } - - /** - * Represents the conditions under which a shader is compiled. - * - * @param materialShader The fragment material shader source. - */ - public record Context(SourceFile materialShader, SourceFile contextShader) { - - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/InstancedArraysCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/InstancedArraysCompiler.java new file mode 100644 index 000000000..0c5625db8 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/compile/InstancedArraysCompiler.java @@ -0,0 +1,248 @@ +package com.jozufozu.flywheel.core.compile; + +import java.util.ArrayList; + +import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.backend.gl.GLSLVersion; +import com.jozufozu.flywheel.backend.gl.shader.GlProgram; +import com.jozufozu.flywheel.backend.gl.shader.GlShader; +import com.jozufozu.flywheel.backend.gl.shader.ShaderType; +import com.jozufozu.flywheel.core.source.CompilationContext; +import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.core.source.SourceFile; +import com.jozufozu.flywheel.core.source.parse.ShaderField; +import com.jozufozu.flywheel.core.source.span.Span; +import com.jozufozu.flywheel.event.ReloadRenderersEvent; +import com.jozufozu.flywheel.util.Pair; + +/** + * A caching compiler. + * + *

+ * This class is responsible for compiling programs on the fly. An instance of this class will keep a cache of + * compiled programs, and will only compile a program if it is not already in the cache. + *

+ *

+ * A ProgramCompiler is also responsible for deleting programs and shaders on renderer reload. + *

+ */ +public class InstancedArraysCompiler extends Memoizer { + + public static final InstancedArraysCompiler INSTANCE = new InstancedArraysCompiler(); + + private final VertexCompiler vertexCompiler; + private final FragmentCompiler fragmentCompiler; + + private InstancedArraysCompiler() { + this.vertexCompiler = new VertexCompiler(); + this.fragmentCompiler = new FragmentCompiler(); + } + + /** + * Get or compile a spec to the given vertex type, accounting for all game state conditions specified by the spec. + * + * @param ctx The context of compilation. + * @return A compiled GlProgram. + */ + public GlProgram getProgram(InstancedArraysCompiler.Context ctx) { + return super.get(ctx); + } + + @Override + public void invalidate() { + super.invalidate(); + vertexCompiler.invalidate(); + fragmentCompiler.invalidate(); + } + + @Override + protected GlProgram _create(InstancedArraysCompiler.Context ctx) { + // TODO: try-catch here to prevent crashing if shaders failed to compile + Material material = ctx.material; + FileResolution instanceShader = ctx.instanceShader(); + ContextShader contextShader = ctx.contextShader; + + var vertex = new VertexCompiler.Context(ctx.vertexType(), instanceShader.getFile(), material.getVertexShader().getFile(), + contextShader.getVertexShader()); + + var fragment = new FragmentCompiler.Context(material.getFragmentShader().getFile(), contextShader.getFragmentShader()); + + return new ProgramAssembler(instanceShader.getFileLoc()) + .attachShader(vertexCompiler.get(vertex)) + .attachShader(fragmentCompiler.get(fragment)) + .link() + .build(contextShader.factory()); + } + + @Override + protected void _destroy(GlProgram value) { + value.delete(); + } + + public static void invalidateAll(ReloadRenderersEvent ignored) { + INSTANCE.invalidate(); + } + + /** + * Represents the entire context of a program's usage. + * + * @param vertexType The vertexType the program should be adapted for. + * @param material The material shader to use. + * @param instanceShader The instance shader to use. + * @param contextShader The context shader to use. + */ + public record Context(VertexType vertexType, Material material, FileResolution instanceShader, + ContextShader contextShader) { + } + + /** + * Handles compilation and deletion of vertex shaders. + */ + public static class VertexCompiler extends Memoizer { + + public VertexCompiler() { + } + + @Override + protected GlShader _create(Context key) { + StringBuilder finalSource = new StringBuilder(); + + finalSource.append(CompileUtil.generateHeader(GLSLVersion.V420, ShaderType.VERTEX)); + + var index = new CompilationContext(); + + // LAYOUT + + var layoutShader = key.vertexType.getLayoutShader().getFile(); + finalSource.append(layoutShader.generateFinalSource(index)); + + // INSTANCE + + int attributeBaseIndex = key.vertexType.getLayout() + .getAttributeCount(); + + var instanceShader = key.instanceShader; + var replacements = new ArrayList>(); + for (ShaderField field : instanceShader.fields.values()) { + if (field.decoration != ShaderField.Decoration.IN) { + continue; + } + + int location = Integer.parseInt(field.location.get()); + int newLocation = location + attributeBaseIndex; + replacements.add(Pair.of(field.location, Integer.toString(newLocation))); + } + finalSource.append(instanceShader.generateFinalSource(index, replacements)); + + // MATERIAL + + var materialShader = key.materialShader; + finalSource.append(materialShader.generateFinalSource(index)); + + // CONTEXT + + var contextShaderSource = key.contextShader; + finalSource.append(contextShaderSource.generateFinalSource(index)); + + // MAIN + + finalSource.append(""" + void main() { + flw_layoutVertex(); + + flw_instanceVertex(); + + flw_materialVertex(); + + flw_contextVertex(); + } + """); + + try { + return new GlShader(finalSource.toString(), ShaderType.VERTEX, ImmutableList.of(layoutShader.name, instanceShader.name, materialShader.name, contextShaderSource.name)); + } catch (ShaderCompilationException e) { + throw e.withErrorLog(index); + } + } + + @Override + protected void _destroy(GlShader value) { + value.delete(); + } + + /** + * @param vertexType The vertex type to use. + * @param instanceShader The instance shader source. + * @param materialShader The vertex material shader source. + * @param contextShader The context shader source. + */ + public record Context(VertexType vertexType, SourceFile instanceShader, SourceFile materialShader, SourceFile contextShader) { + } + } + + /** + * Handles compilation and deletion of fragment shaders. + */ + public static class FragmentCompiler extends Memoizer { + + public FragmentCompiler() { + } + + @Override + protected GlShader _create(Context key) { + StringBuilder finalSource = new StringBuilder(); + + finalSource.append(CompileUtil.generateHeader(GLSLVersion.V420, ShaderType.FRAGMENT)); + + var ctx = new CompilationContext(); + + // MATERIAL + + SourceFile materialShader = key.materialShader; + finalSource.append(materialShader.generateFinalSource(ctx)); + + // CONTEXT + + SourceFile contextShaderSource = key.contextShader; + finalSource.append(contextShaderSource.generateFinalSource(ctx)); + + // MAIN + + finalSource.append(generateFooter()); + + try { + return new GlShader(finalSource.toString(), ShaderType.FRAGMENT, ImmutableList.of(materialShader.name, contextShaderSource.name)); + } catch (ShaderCompilationException e) { + throw e.withErrorLog(ctx); + } + } + + protected String generateFooter() { + return """ + void main() { + flw_initFragment(); + + flw_materialFragment(); + + flw_contextFragment(); + } + """; + } + + @Override + protected void _destroy(GlShader value) { + value.delete(); + } + + /** + * Represents the conditions under which a shader is compiled. + * + * @param materialShader The fragment material shader source. + */ + public record Context(SourceFile materialShader, SourceFile contextShader) { + + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java deleted file mode 100644 index 4b54c2218..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/compile/ProgramCompiler.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.jozufozu.flywheel.core.compile; - -import com.jozufozu.flywheel.api.material.Material; -import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; -import com.jozufozu.flywheel.core.source.FileResolution; -import com.jozufozu.flywheel.event.ReloadRenderersEvent; - -/** - * A caching compiler. - * - *

- * This class is responsible for compiling programs on the fly. An instance of this class will keep a cache of - * compiled programs, and will only compile a program if it is not already in the cache. - *

- *

- * A ProgramCompiler is also responsible for deleting programs and shaders on renderer reload. - *

- */ -public class ProgramCompiler extends Memoizer { - - public static final ProgramCompiler INSTANCE = new ProgramCompiler(); - - private final VertexCompiler vertexCompiler; - private final FragmentCompiler fragmentCompiler; - - private ProgramCompiler() { - this.vertexCompiler = new VertexCompiler(); - this.fragmentCompiler = new FragmentCompiler(); - } - - /** - * Get or compile a spec to the given vertex type, accounting for all game state conditions specified by the spec. - * - * @param ctx The context of compilation. - * @return A compiled GlProgram. - */ - public GlProgram getProgram(ProgramCompiler.Context ctx) { - return super.get(ctx); - } - - @Override - public void invalidate() { - super.invalidate(); - vertexCompiler.invalidate(); - fragmentCompiler.invalidate(); - } - - @Override - protected GlProgram _create(ProgramCompiler.Context ctx) { - // TODO: try-catch here to prevent crashing if shaders failed to compile - Material material = ctx.material; - FileResolution instanceShader = ctx.instanceShader(); - ContextShader contextShader = ctx.contextShader; - - var vertex = new VertexCompiler.Context(ctx.vertexType(), instanceShader.getFile(), material.getVertexShader().getFile(), - contextShader.getVertexShader()); - - var fragment = new FragmentCompiler.Context(material.getFragmentShader().getFile(), contextShader.getFragmentShader()); - - return new ProgramAssembler(instanceShader.getFileLoc()) - .attachShader(vertexCompiler.get(vertex)) - .attachShader(fragmentCompiler.get(fragment)) - .link() - .build(contextShader.factory()); - } - - @Override - protected void _destroy(GlProgram value) { - value.delete(); - } - - public static void invalidateAll(ReloadRenderersEvent ignored) { - INSTANCE.invalidate(); - } - - /** - * Represents the entire context of a program's usage. - * - * @param vertexType The vertexType the program should be adapted for. - * @param material The material shader to use. - * @param instanceShader The instance shader to use. - * @param contextShader The context shader to use. - */ - public record Context(VertexType vertexType, Material material, FileResolution instanceShader, - ContextShader contextShader) { - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java deleted file mode 100644 index 50aba6150..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/compile/VertexCompiler.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.jozufozu.flywheel.core.compile; - -import java.util.ArrayList; - -import com.google.common.collect.ImmutableList; -import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.backend.gl.GLSLVersion; -import com.jozufozu.flywheel.backend.gl.shader.GlShader; -import com.jozufozu.flywheel.backend.gl.shader.ShaderType; -import com.jozufozu.flywheel.core.source.CompilationContext; -import com.jozufozu.flywheel.core.source.SourceFile; -import com.jozufozu.flywheel.core.source.parse.ShaderField; -import com.jozufozu.flywheel.core.source.span.Span; -import com.jozufozu.flywheel.util.Pair; - -/** - * Handles compilation and deletion of vertex shaders. - */ -public class VertexCompiler extends Memoizer { - - public VertexCompiler() { - } - - @Override - protected GlShader _create(Context key) { - StringBuilder finalSource = new StringBuilder(); - - finalSource.append(CompileUtil.generateHeader(GLSLVersion.V420, ShaderType.VERTEX)); - - var index = new CompilationContext(); - - // LAYOUT - - var layoutShader = key.vertexType.getLayoutShader().getFile(); - finalSource.append(layoutShader.generateFinalSource(index)); - - // INSTANCE - - int attributeBaseIndex = key.vertexType.getLayout() - .getAttributeCount(); - - var instanceShader = key.instanceShader; - var replacements = new ArrayList>(); - for (ShaderField field : instanceShader.fields.values()) { - if (field.decoration != ShaderField.Decoration.IN) { - continue; - } - - int location = Integer.parseInt(field.location.get()); - int newLocation = location + attributeBaseIndex; - replacements.add(Pair.of(field.location, Integer.toString(newLocation))); - } - finalSource.append(instanceShader.generateFinalSource(index, replacements)); - - // MATERIAL - - var materialShader = key.materialShader; - finalSource.append(materialShader.generateFinalSource(index)); - - // CONTEXT - - var contextShaderSource = key.contextShader; - finalSource.append(contextShaderSource.generateFinalSource(index)); - - // MAIN - - finalSource.append(""" - void main() { - flw_layoutVertex(); - - flw_instanceVertex(); - - flw_materialVertex(); - - flw_contextVertex(); - } - """); - - try { - return new GlShader(finalSource.toString(), ShaderType.VERTEX, ImmutableList.of(layoutShader.name, instanceShader.name, materialShader.name, contextShaderSource.name)); - } catch (ShaderCompilationException e) { - throw e.withErrorLog(index); - } - } - - @Override - protected void _destroy(GlShader value) { - value.delete(); - } - - /** - * @param vertexType The vertex type to use. - * @param instanceShader The instance shader source. - * @param materialShader The vertex material shader source. - * @param contextShader The context shader source. - */ - public record Context(VertexType vertexType, SourceFile instanceShader, SourceFile materialShader, SourceFile contextShader) { - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingInstanceManager.java b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingInstanceManager.java deleted file mode 100644 index c58b5984d..000000000 --- a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingInstanceManager.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.jozufozu.flywheel.core.crumbling; - -import com.jozufozu.flywheel.api.instance.DynamicInstance; -import com.jozufozu.flywheel.api.instancer.InstancerManager; -import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceManager; - -public class CrumblingInstanceManager extends BlockEntityInstanceManager { - - public CrumblingInstanceManager(InstancerManager instancerManager) { - super(instancerManager); - } - - @Override - protected void updateInstance(DynamicInstance dyn, float lookX, float lookY, float lookZ, int cX, int cY, int cZ) { - dyn.beginFrame(); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java index 7459758f5..595179b9f 100644 --- a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java +++ b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java @@ -8,6 +8,8 @@ import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.gl.GlStateTracker; import com.jozufozu.flywheel.backend.instancing.InstanceManager; import com.jozufozu.flywheel.backend.instancing.SerialTaskEngine; +import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceManager; +import com.jozufozu.flywheel.backend.instancing.instancing.DrawCall; import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine; import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.RenderContext; @@ -128,7 +130,7 @@ public class CrumblingRenderer { private State() { instancerManager = new CrumblingEngine(); - instanceManager = new CrumblingInstanceManager(instancerManager); + instanceManager = new BlockEntityInstanceManager(instancerManager); instancerManager.attachManagers(instanceManager); } diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedWriterUnsafe.java b/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedWriterUnsafe.java index 8634e0db7..9aab8c48b 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedWriterUnsafe.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/model/TransformedWriterUnsafe.java @@ -4,7 +4,7 @@ import java.nio.ByteBuffer; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.core.structs.ColoredLitWriterUnsafe; -import com.jozufozu.flywheel.util.MatrixWrite; +import com.jozufozu.flywheel.util.extension.MatrixExtension; public class TransformedWriterUnsafe extends ColoredLitWriterUnsafe { @@ -17,7 +17,7 @@ public class TransformedWriterUnsafe extends ColoredLitWriterUnsafe implements Supplier { return value; } + public boolean isInitialized() { + return value != null; + } + public Lazy lazyMap(Function func) { return new Lazy<>(() -> func.apply(get())); } diff --git a/src/main/java/com/jozufozu/flywheel/util/ClientLevelExtension.java b/src/main/java/com/jozufozu/flywheel/util/extension/ClientLevelExtension.java similarity index 94% rename from src/main/java/com/jozufozu/flywheel/util/ClientLevelExtension.java rename to src/main/java/com/jozufozu/flywheel/util/extension/ClientLevelExtension.java index 197e24a27..d6e6e8bd5 100644 --- a/src/main/java/com/jozufozu/flywheel/util/ClientLevelExtension.java +++ b/src/main/java/com/jozufozu/flywheel/util/extension/ClientLevelExtension.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.util; +package com.jozufozu.flywheel.util.extension; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.world.entity.Entity; diff --git a/src/main/java/com/jozufozu/flywheel/util/extension/Matrix3fExtension.java b/src/main/java/com/jozufozu/flywheel/util/extension/Matrix3fExtension.java new file mode 100644 index 000000000..a587ec537 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/util/extension/Matrix3fExtension.java @@ -0,0 +1,16 @@ +package com.jozufozu.flywheel.util.extension; + +import com.jozufozu.flywheel.util.joml.Matrix3f; + +public interface Matrix3fExtension { + + Matrix3f flywheel$store(Matrix3f matrix); + + static Matrix3f clone(com.mojang.math.Matrix3f moj) { + return ((Matrix3fExtension)(Object) moj).flywheel$store(new Matrix3f()); + } + + static void store(com.mojang.math.Matrix3f moj, Matrix3f joml) { + ((Matrix3fExtension)(Object) moj).flywheel$store(joml); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/util/extension/Matrix4fExtension.java b/src/main/java/com/jozufozu/flywheel/util/extension/Matrix4fExtension.java new file mode 100644 index 000000000..7651cf622 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/util/extension/Matrix4fExtension.java @@ -0,0 +1,16 @@ +package com.jozufozu.flywheel.util.extension; + +import com.jozufozu.flywheel.util.joml.Matrix4f; + +public interface Matrix4fExtension { + + Matrix4f flywheel$store(Matrix4f matrix); + + static Matrix4f clone(com.mojang.math.Matrix4f moj) { + return ((Matrix4fExtension)(Object) moj).flywheel$store(new Matrix4f()); + } + + static void store(com.mojang.math.Matrix4f moj, Matrix4f joml) { + ((Matrix4fExtension)(Object) moj).flywheel$store(joml); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/util/MatrixWrite.java b/src/main/java/com/jozufozu/flywheel/util/extension/MatrixExtension.java similarity index 70% rename from src/main/java/com/jozufozu/flywheel/util/MatrixWrite.java rename to src/main/java/com/jozufozu/flywheel/util/extension/MatrixExtension.java index e5455dad5..4dd0ac116 100644 --- a/src/main/java/com/jozufozu/flywheel/util/MatrixWrite.java +++ b/src/main/java/com/jozufozu/flywheel/util/extension/MatrixExtension.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.util; +package com.jozufozu.flywheel.util.extension; import java.nio.ByteBuffer; @@ -8,7 +8,7 @@ import com.mojang.math.Matrix4f; * @see com.jozufozu.flywheel.mixin.matrix.Matrix3fMixin * @see com.jozufozu.flywheel.mixin.matrix.Matrix4fMixin */ -public interface MatrixWrite { +public interface MatrixExtension { /** * Write the contents of this object into sequential memory starting at the given address. @@ -18,10 +18,10 @@ public interface MatrixWrite { void flywheel$write(ByteBuffer buf); static void write(Matrix4f matrix, ByteBuffer buf) { - ((MatrixWrite) (Object) matrix).flywheel$write(buf); + ((MatrixExtension) (Object) matrix).flywheel$write(buf); } static void writeUnsafe(Matrix4f matrix, long ptr) { - ((MatrixWrite) (Object) matrix).flywheel$writeUnsafe(ptr); + ((MatrixExtension) (Object) matrix).flywheel$writeUnsafe(ptr); } } diff --git a/src/main/java/com/jozufozu/flywheel/util/RenderTypeExtension.java b/src/main/java/com/jozufozu/flywheel/util/extension/RenderTypeExtension.java similarity index 93% rename from src/main/java/com/jozufozu/flywheel/util/RenderTypeExtension.java rename to src/main/java/com/jozufozu/flywheel/util/extension/RenderTypeExtension.java index 5beefc1f2..6398bb479 100644 --- a/src/main/java/com/jozufozu/flywheel/util/RenderTypeExtension.java +++ b/src/main/java/com/jozufozu/flywheel/util/extension/RenderTypeExtension.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.util; +package com.jozufozu.flywheel.util.extension; import com.jozufozu.flywheel.backend.instancing.batching.DrawBuffer; diff --git a/src/main/java/com/jozufozu/flywheel/util/joml/FrustumIntersection.java b/src/main/java/com/jozufozu/flywheel/util/joml/FrustumIntersection.java index a85b90676..3bb149f9c 100644 --- a/src/main/java/com/jozufozu/flywheel/util/joml/FrustumIntersection.java +++ b/src/main/java/com/jozufozu/flywheel/util/joml/FrustumIntersection.java @@ -23,6 +23,9 @@ */ package com.jozufozu.flywheel.util.joml; +import java.nio.ByteBuffer; + +import org.lwjgl.system.MemoryUtil; /** * Efficiently performs frustum intersection tests by caching the frustum planes of an arbitrary transformation {@link Matrix4fc matrix}. *

@@ -950,4 +953,40 @@ public class FrustumIntersection { return da >= 0.0f || db >= 0.0f; } + public void bufferPlanes(ByteBuffer buffer) { + + Vector3f scratch = new Vector3f(); + Vector3f result = new Vector3f(); + + long addr = MemoryUtil.memAddress(buffer); + planeIntersect(planes[0], planes[2], planes[4], result, scratch); result.getToAddress(addr); + planeIntersect(planes[0], planes[2], planes[5], result, scratch); result.getToAddress(addr + 12); + planeIntersect(planes[0], planes[3], planes[4], result, scratch); result.getToAddress(addr + 24); + planeIntersect(planes[0], planes[3], planes[5], result, scratch); result.getToAddress(addr + 36); + planeIntersect(planes[1], planes[2], planes[4], result, scratch); result.getToAddress(addr + 48); + planeIntersect(planes[1], planes[2], planes[5], result, scratch); result.getToAddress(addr + 60); + planeIntersect(planes[1], planes[3], planes[4], result, scratch); result.getToAddress(addr + 72); + planeIntersect(planes[1], planes[3], planes[5], result, scratch); result.getToAddress(addr + 84); + } + + private Vector3f planeIntersect(Vector4f a, Vector4f b, Vector4f c, Vector3f result, Vector3f scratch) { + // Formula used + // d1 ( N2 * N3 ) + d2 ( N3 * N1 ) + d3 ( N1 * N2 ) + //P = --------------------------------------------------------------------- + // N1 . ( N2 * N3 ) + // + // Note: N refers to the normal, d refers to the displacement. '.' means dot product. '*' means cross product + + float f = result.set(b.x, b.y, b.z).cross(c.x, c.y, c.z).dot(a.x, a.y, a.z); + + result.set(0); + scratch.set(b.x, b.y, b.z).cross(c.x, c.y, c.z).mul(a.z); + result.add(scratch); + scratch.set(c.x, c.y, c.z).cross(a.x, a.y, a.z).mul(b.z); + result.add(scratch); + scratch.set(a.x, a.y, a.z).cross(b.x, b.y, b.z).mul(c.z); + result.add(scratch); + + return result.div(f); + } } diff --git a/src/main/java/com/jozufozu/flywheel/util/joml/Quaternionf.java b/src/main/java/com/jozufozu/flywheel/util/joml/Quaternionf.java index f783ca20e..ad2ef13cd 100644 --- a/src/main/java/com/jozufozu/flywheel/util/joml/Quaternionf.java +++ b/src/main/java/com/jozufozu/flywheel/util/joml/Quaternionf.java @@ -32,6 +32,8 @@ import java.nio.FloatBuffer; import java.text.DecimalFormat; import java.text.NumberFormat; +import com.mojang.math.Quaternion; + /** * Quaternion of 4 single-precision floats which can represent rotation and uniform scaling. * @@ -130,6 +132,13 @@ public class Quaternionf implements Externalizable, Cloneable, Quaternionfc { w = cos; } + public Quaternionf(Quaternion moj) { + x = moj.i(); + y = moj.j(); + z = moj.k(); + w = moj.r(); + } + /** * @return the first component of the vector part */ diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/effect/ExampleEffect.java b/src/main/java/com/jozufozu/flywheel/vanilla/effect/ExampleEffect.java index 5c583534c..d7f362424 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/effect/ExampleEffect.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/effect/ExampleEffect.java @@ -18,6 +18,7 @@ import com.jozufozu.flywheel.event.ReloadRenderersEvent; import com.jozufozu.flywheel.util.AnimationTickHolder; import com.jozufozu.flywheel.util.box.GridAlignedBB; import com.jozufozu.flywheel.util.box.ImmutableBox; +import com.jozufozu.flywheel.util.joml.FrustumIntersection; import com.jozufozu.flywheel.util.joml.Vector3f; import net.minecraft.client.Minecraft; @@ -297,5 +298,10 @@ public class ExampleEffect implements Effect { public boolean decreaseFramerateWithDistance() { return false; } + + @Override + public boolean checkFrustum(FrustumIntersection frustum) { + return true; + } } } diff --git a/src/main/resources/assets/flywheel/flywheel/debug/debug.frag b/src/main/resources/assets/flywheel/flywheel/debug/debug.frag new file mode 100644 index 000000000..ab41dc91f --- /dev/null +++ b/src/main/resources/assets/flywheel/flywheel/debug/debug.frag @@ -0,0 +1,5 @@ +out vec4 fragColor; + +void main() { + fragColor = vec4(1.0, 1.0, 1.0, 0.2); +} diff --git a/src/main/resources/assets/flywheel/flywheel/debug/debug.vert b/src/main/resources/assets/flywheel/flywheel/debug/debug.vert new file mode 100644 index 000000000..6a5d60ca1 --- /dev/null +++ b/src/main/resources/assets/flywheel/flywheel/debug/debug.vert @@ -0,0 +1,7 @@ +#use "flywheel:uniform/view.glsl" + +layout(location = 0) in vec3 worldPos; + +void main() { + gl_Position = flw_viewProjection * vec4(worldPos, 1.0); +}