mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-22 19:07:54 +01:00
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
This commit is contained in:
parent
ed3aca8bfc
commit
4ec1f8eaf3
36 changed files with 648 additions and 387 deletions
|
@ -12,15 +12,15 @@ 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;
|
||||||
import com.jozufozu.flywheel.core.Components;
|
import com.jozufozu.flywheel.core.Components;
|
||||||
|
import com.jozufozu.flywheel.core.DebugRender;
|
||||||
import com.jozufozu.flywheel.core.PartialModel;
|
import com.jozufozu.flywheel.core.PartialModel;
|
||||||
import com.jozufozu.flywheel.core.QuadConverter;
|
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.InstancedArraysCompiler;
|
||||||
import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer;
|
import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer;
|
||||||
import com.jozufozu.flywheel.core.model.Models;
|
import com.jozufozu.flywheel.core.model.Models;
|
||||||
import com.jozufozu.flywheel.event.EntityWorldHandler;
|
import com.jozufozu.flywheel.event.EntityWorldHandler;
|
||||||
import com.jozufozu.flywheel.event.ForgeEvents;
|
import com.jozufozu.flywheel.event.ForgeEvents;
|
||||||
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;
|
||||||
import com.mojang.logging.LogUtils;
|
import com.mojang.logging.LogUtils;
|
||||||
|
@ -80,7 +80,7 @@ public class Flywheel {
|
||||||
forgeEventBus.addListener(FlwCommands::registerClientCommands);
|
forgeEventBus.addListener(FlwCommands::registerClientCommands);
|
||||||
|
|
||||||
forgeEventBus.addListener(EventPriority.HIGHEST, QuadConverter::onRendererReload);
|
forgeEventBus.addListener(EventPriority.HIGHEST, QuadConverter::onRendererReload);
|
||||||
forgeEventBus.<ReloadRenderersEvent>addListener(ProgramCompiler::invalidateAll);
|
forgeEventBus.addListener(InstancedArraysCompiler::invalidateAll);
|
||||||
forgeEventBus.addListener(Models::onReload);
|
forgeEventBus.addListener(Models::onReload);
|
||||||
forgeEventBus.addListener(MeshPool::reset);
|
forgeEventBus.addListener(MeshPool::reset);
|
||||||
forgeEventBus.addListener(CrumblingRenderer::onReloadRenderers);
|
forgeEventBus.addListener(CrumblingRenderer::onReloadRenderers);
|
||||||
|
@ -108,6 +108,7 @@ public class Flywheel {
|
||||||
// forgeEventBus.addListener(ExampleEffect::onReload);
|
// forgeEventBus.addListener(ExampleEffect::onReload);
|
||||||
|
|
||||||
Components.init();
|
Components.init();
|
||||||
|
DebugRender.init();
|
||||||
|
|
||||||
VanillaInstances.init();
|
VanillaInstances.init();
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
package com.jozufozu.flywheel.api.instance;
|
package com.jozufozu.flywheel.api.instance;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.util.joml.FrustumIntersection;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
|
||||||
public interface Instance {
|
public interface Instance {
|
||||||
BlockPos getWorldPosition();
|
BlockPos getWorldPosition();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check this instance against a frustum.<p>
|
||||||
|
* 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();
|
boolean isRemoved();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||||
import com.jozufozu.flywheel.core.ComponentRegistry;
|
import com.jozufozu.flywheel.core.ComponentRegistry;
|
||||||
import com.jozufozu.flywheel.core.compile.ContextShader;
|
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.crumbling.CrumblingRenderer;
|
||||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||||
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
|
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
|
||||||
|
@ -70,8 +70,8 @@ public class Loader implements ResourceManagerReloadListener {
|
||||||
for (StructType<?> structType : ComponentRegistry.structTypes) {
|
for (StructType<?> structType : ComponentRegistry.structTypes) {
|
||||||
for (VertexType vertexType : ComponentRegistry.vertexTypes) {
|
for (VertexType vertexType : ComponentRegistry.vertexTypes) {
|
||||||
for (ContextShader contextShader : ComponentRegistry.contextShaders) {
|
for (ContextShader contextShader : ComponentRegistry.contextShaders) {
|
||||||
var ctx = new ProgramCompiler.Context(vertexType, material, structType.getInstanceShader(), contextShader);
|
var ctx = new InstancedArraysCompiler.Context(vertexType, material, structType.getInstanceShader(), contextShader);
|
||||||
ProgramCompiler.INSTANCE.getProgram(ctx);
|
InstancedArraysCompiler.INSTANCE.getProgram(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,25 +5,19 @@ import static org.lwjgl.opengl.GL20.glGetUniformLocation;
|
||||||
import static org.lwjgl.opengl.GL20.glUniform1i;
|
import static org.lwjgl.opengl.GL20.glUniform1i;
|
||||||
import static org.lwjgl.opengl.GL20.glUniformMatrix4fv;
|
import static org.lwjgl.opengl.GL20.glUniformMatrix4fv;
|
||||||
|
|
||||||
import java.nio.FloatBuffer;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.lwjgl.system.MemoryStack;
|
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.Backend;
|
import com.jozufozu.flywheel.backend.Backend;
|
||||||
import com.jozufozu.flywheel.backend.gl.GlObject;
|
import com.jozufozu.flywheel.backend.gl.GlObject;
|
||||||
import com.mojang.blaze3d.shaders.ProgramManager;
|
import com.mojang.blaze3d.shaders.ProgramManager;
|
||||||
import com.mojang.math.Matrix4f;
|
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
public abstract class GlProgram extends GlObject {
|
public class GlProgram extends GlObject {
|
||||||
private static final FloatBuffer floatBuffer = MemoryStack.stackGet()
|
|
||||||
.mallocFloat(16);
|
|
||||||
|
|
||||||
public final ResourceLocation name;
|
public final ResourceLocation name;
|
||||||
|
|
||||||
protected GlProgram(ResourceLocation name, int handle) {
|
public GlProgram(ResourceLocation name, int handle) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
setHandle(handle);
|
setHandle(handle);
|
||||||
}
|
}
|
||||||
|
@ -70,11 +64,6 @@ public abstract class GlProgram extends GlObject {
|
||||||
return samplerUniform;
|
return samplerUniform;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void uploadMatrixUniform(int uniform, Matrix4f mat) {
|
|
||||||
mat.store(floatBuffer);
|
|
||||||
glUniformMatrix4fv(uniform, false, floatBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deleteInternal(int handle) {
|
protected void deleteInternal(int handle) {
|
||||||
glDeleteProgram(handle);
|
glDeleteProgram(handle);
|
||||||
|
|
|
@ -15,9 +15,8 @@ import com.jozufozu.flywheel.backend.instancing.ratelimit.NonLimiter;
|
||||||
import com.jozufozu.flywheel.config.FlwConfig;
|
import com.jozufozu.flywheel.config.FlwConfig;
|
||||||
import com.jozufozu.flywheel.core.RenderContext;
|
import com.jozufozu.flywheel.core.RenderContext;
|
||||||
import com.jozufozu.flywheel.light.LightUpdater;
|
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;
|
import net.minecraft.core.BlockPos;
|
||||||
|
|
||||||
public abstract class InstanceManager<T> {
|
public abstract class InstanceManager<T> {
|
||||||
|
@ -100,27 +99,26 @@ public abstract class InstanceManager<T> {
|
||||||
int dY = pos.getY() - cY;
|
int dY = pos.getY() - cY;
|
||||||
int dZ = pos.getZ() - cZ;
|
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) {
|
public void beginFrame(TaskEngine taskEngine, RenderContext context) {
|
||||||
frame.tick();
|
frame.tick();
|
||||||
processQueuedAdditions();
|
processQueuedAdditions();
|
||||||
|
|
||||||
Camera camera = context.camera();
|
|
||||||
Vector3f look = camera.getLookVector();
|
|
||||||
float lookX = look.x();
|
|
||||||
float lookY = look.y();
|
|
||||||
float lookZ = look.z();
|
|
||||||
|
|
||||||
// integer camera pos
|
// integer camera pos
|
||||||
BlockPos cameraIntPos = camera.getBlockPosition();
|
BlockPos cameraIntPos = context.camera().getBlockPosition();
|
||||||
int cX = cameraIntPos.getX();
|
int cX = cameraIntPos.getX();
|
||||||
int cY = cameraIntPos.getY();
|
int cY = cameraIntPos.getY();
|
||||||
int cZ = cameraIntPos.getZ();
|
int cZ = cameraIntPos.getZ();
|
||||||
|
FrustumIntersection culler = context.culler();
|
||||||
|
|
||||||
var instances = getStorage().getInstancesForUpdate();
|
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 <I> void distributeWork(TaskEngine taskEngine, List<I> instances, Consumer<I> action) {
|
private static <I> void distributeWork(TaskEngine taskEngine, List<I> instances, Consumer<I> action) {
|
||||||
|
@ -140,7 +138,7 @@ public abstract class InstanceManager<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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()) {
|
if (!dyn.decreaseFramerateWithDistance()) {
|
||||||
dyn.beginFrame();
|
dyn.beginFrame();
|
||||||
return;
|
return;
|
||||||
|
@ -151,15 +149,14 @@ public abstract class InstanceManager<T> {
|
||||||
int dY = worldPos.getY() - cY;
|
int dY = worldPos.getY() - cY;
|
||||||
int dZ = worldPos.getZ() - cZ;
|
int dZ = worldPos.getZ() - cZ;
|
||||||
|
|
||||||
// is it more than 2 blocks behind the camera?
|
if (!frame.shouldUpdate(dX, dY, dZ)) {
|
||||||
int dist = 2;
|
|
||||||
float dot = (dX + lookX * dist) * lookX + (dY + lookY * dist) * lookY + (dZ + lookZ * dist) * lookZ;
|
|
||||||
if (dot < 0) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame.shouldUpdate(dX, dY, dZ))
|
if (dyn.checkFrustum(test)) {
|
||||||
dyn.beginFrame();
|
dyn.beginFrame();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(T obj) {
|
public void add(T obj) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
|
||||||
import com.jozufozu.flywheel.core.Components;
|
import com.jozufozu.flywheel.core.Components;
|
||||||
import com.jozufozu.flywheel.core.RenderContext;
|
import com.jozufozu.flywheel.core.RenderContext;
|
||||||
import com.jozufozu.flywheel.event.BeginFrameEvent;
|
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.Minecraft;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
|
@ -133,10 +133,7 @@ public class InstanceWorld {
|
||||||
*/
|
*/
|
||||||
public void renderStage(RenderContext context, RenderStage stage) {
|
public void renderStage(RenderContext context, RenderStage stage) {
|
||||||
taskEngine.syncPoint();
|
taskEngine.syncPoint();
|
||||||
context.pushPose();
|
|
||||||
context.translateBack(context.camera().getPosition());
|
|
||||||
engine.renderStage(taskEngine, context, stage);
|
engine.renderStage(taskEngine, context, stage);
|
||||||
context.popPose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,6 +14,7 @@ import com.jozufozu.flywheel.core.structs.model.TransformedPart;
|
||||||
import com.jozufozu.flywheel.core.structs.oriented.OrientedPart;
|
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;
|
||||||
|
import com.jozufozu.flywheel.util.joml.FrustumIntersection;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
@ -90,16 +91,13 @@ public abstract class BlockEntityInstance<T extends BlockEntity> extends Abstrac
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InstancerFactory<TransformedPart> getTransformFactory() {
|
|
||||||
return instancerManager.factory(StructTypes.TRANSFORMED);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected InstancerFactory<OrientedPart> getOrientedFactory() {
|
|
||||||
return instancerManager.factory(StructTypes.ORIENTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImmutableBox getVolume() {
|
public ImmutableBox getVolume() {
|
||||||
return GridAlignedBB.from(pos);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceM
|
||||||
import com.jozufozu.flywheel.light.LightListener;
|
import com.jozufozu.flywheel.light.LightListener;
|
||||||
import com.jozufozu.flywheel.light.TickingLightListener;
|
import com.jozufozu.flywheel.light.TickingLightListener;
|
||||||
import com.jozufozu.flywheel.util.box.GridAlignedBB;
|
import com.jozufozu.flywheel.util.box.GridAlignedBB;
|
||||||
|
import com.jozufozu.flywheel.util.joml.FrustumIntersection;
|
||||||
import com.mojang.math.Vector3f;
|
import com.mojang.math.Vector3f;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
@ -96,4 +97,11 @@ public abstract class EntityInstance<E extends Entity> extends AbstractInstance
|
||||||
public BlockPos getWorldPosition() {
|
public BlockPos getWorldPosition() {
|
||||||
return entity.blockPosition();
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import com.jozufozu.flywheel.backend.instancing.InstanceManager;
|
||||||
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||||
import com.jozufozu.flywheel.core.RenderContext;
|
import com.jozufozu.flywheel.core.RenderContext;
|
||||||
import com.jozufozu.flywheel.core.compile.ContextShader;
|
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.source.FileResolution;
|
||||||
import com.jozufozu.flywheel.core.uniform.UniformBuffer;
|
import com.jozufozu.flywheel.core.uniform.UniformBuffer;
|
||||||
import com.jozufozu.flywheel.util.WeakHashSet;
|
import com.jozufozu.flywheel.util.WeakHashSet;
|
||||||
|
@ -137,9 +137,9 @@ public class InstancingEngine implements Engine {
|
||||||
.getInstanceShader();
|
.getInstanceShader();
|
||||||
Material material = desc.material();
|
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();
|
.bind();
|
||||||
UniformBuffer.getInstance().sync();
|
UniformBuffer.getInstance().sync();
|
||||||
}
|
}
|
||||||
|
|
104
src/main/java/com/jozufozu/flywheel/core/DebugRender.java
Normal file
104
src/main/java/com/jozufozu/flywheel/core/DebugRender.java
Normal file
|
@ -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<GlProgram> SHADER = Lazy.of(() -> DebugCompiler.INSTANCE.get(new DebugCompiler.Context(Files.VERTEX, Files.FRAGMENT)));
|
||||||
|
|
||||||
|
private static final Lazy<Frustum> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,56 +2,19 @@ package com.jozufozu.flywheel.core;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
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.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.math.Matrix3f;
|
|
||||||
import com.mojang.math.Matrix4f;
|
import com.mojang.math.Matrix4f;
|
||||||
import com.mojang.math.Quaternion;
|
|
||||||
|
|
||||||
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.LevelRenderer;
|
||||||
import net.minecraft.client.renderer.RenderBuffers;
|
import net.minecraft.client.renderer.RenderBuffers;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
public record RenderContext(LevelRenderer renderer, ClientLevel level, PoseStack stack, Matrix4f viewProjection,
|
public record RenderContext(LevelRenderer renderer, ClientLevel level, PoseStack stack, Matrix4f viewProjection,
|
||||||
Matrix4f projection, RenderBuffers buffers, Camera camera) implements TransformStack {
|
Matrix4f projection, RenderBuffers buffers, Camera camera, FrustumIntersection culler) {
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static Matrix4f createViewProjection(PoseStack view, Matrix4f projection) {
|
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());
|
viewProjection.multiply(view.last().pose());
|
||||||
return viewProjection;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.<p>
|
||||||
|
* Useful for writing experimental shaders or
|
||||||
|
*/
|
||||||
|
public class DebugCompiler extends Memoizer<DebugCompiler.Context, GlProgram> {
|
||||||
|
|
||||||
|
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<ShaderCompiler.Context, GlShader> {
|
||||||
|
|
||||||
|
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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<FragmentCompiler.Context, GlShader> {
|
|
||||||
|
|
||||||
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) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* A ProgramCompiler is also responsible for deleting programs and shaders on renderer reload.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class InstancedArraysCompiler extends Memoizer<InstancedArraysCompiler.Context, GlProgram> {
|
||||||
|
|
||||||
|
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<VertexCompiler.Context, GlShader> {
|
||||||
|
|
||||||
|
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<Pair<Span, String>>();
|
||||||
|
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<FragmentCompiler.Context, GlShader> {
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 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.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* A ProgramCompiler is also responsible for deleting programs and shaders on renderer reload.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public class ProgramCompiler extends Memoizer<ProgramCompiler.Context, GlProgram> {
|
|
||||||
|
|
||||||
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) {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<VertexCompiler.Context, GlShader> {
|
|
||||||
|
|
||||||
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<Pair<Span, String>>();
|
|
||||||
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) {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,6 +8,8 @@ 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;
|
||||||
import com.jozufozu.flywheel.backend.instancing.SerialTaskEngine;
|
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.backend.instancing.instancing.InstancingEngine;
|
||||||
import com.jozufozu.flywheel.core.Components;
|
import com.jozufozu.flywheel.core.Components;
|
||||||
import com.jozufozu.flywheel.core.RenderContext;
|
import com.jozufozu.flywheel.core.RenderContext;
|
||||||
|
@ -128,7 +130,7 @@ public class CrumblingRenderer {
|
||||||
|
|
||||||
private State() {
|
private State() {
|
||||||
instancerManager = new CrumblingEngine();
|
instancerManager = new CrumblingEngine();
|
||||||
instanceManager = new CrumblingInstanceManager(instancerManager);
|
instanceManager = new BlockEntityInstanceManager(instancerManager);
|
||||||
instancerManager.attachManagers(instanceManager);
|
instancerManager.attachManagers(instanceManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.struct.StructType;
|
import com.jozufozu.flywheel.api.struct.StructType;
|
||||||
import com.jozufozu.flywheel.core.structs.ColoredLitWriterUnsafe;
|
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<TransformedPart> {
|
public class TransformedWriterUnsafe extends ColoredLitWriterUnsafe<TransformedPart> {
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ public class TransformedWriterUnsafe extends ColoredLitWriterUnsafe<TransformedP
|
||||||
super.writeInternal(d);
|
super.writeInternal(d);
|
||||||
long ptr = writePointer + 6;
|
long ptr = writePointer + 6;
|
||||||
|
|
||||||
((MatrixWrite) (Object) d.model).flywheel$writeUnsafe(ptr);
|
((MatrixExtension) (Object) d.model).flywheel$writeUnsafe(ptr);
|
||||||
((MatrixWrite) (Object) d.normal).flywheel$writeUnsafe(ptr + 4 * 16);
|
((MatrixExtension) (Object) d.normal).flywheel$writeUnsafe(ptr + 4 * 16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import com.jozufozu.flywheel.core.Components;
|
||||||
import com.jozufozu.flywheel.core.RenderContext;
|
import com.jozufozu.flywheel.core.RenderContext;
|
||||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||||
import com.jozufozu.flywheel.event.BeginFrameEvent;
|
import com.jozufozu.flywheel.event.BeginFrameEvent;
|
||||||
import com.jozufozu.flywheel.util.MatrixWrite;
|
import com.jozufozu.flywheel.util.extension.MatrixExtension;
|
||||||
|
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.core.Vec3i;
|
import net.minecraft.core.Vec3i;
|
||||||
|
@ -54,7 +54,7 @@ public class ViewProvider extends UniformProvider {
|
||||||
|
|
||||||
long ptr = MemoryUtil.memAddress(buffer);
|
long ptr = MemoryUtil.memAddress(buffer);
|
||||||
|
|
||||||
MatrixWrite.writeUnsafe(vp, ptr);
|
MatrixExtension.writeUnsafe(vp, ptr);
|
||||||
MemoryUtil.memPutFloat(ptr + 64, camX);
|
MemoryUtil.memPutFloat(ptr + 64, camX);
|
||||||
MemoryUtil.memPutFloat(ptr + 68, camY);
|
MemoryUtil.memPutFloat(ptr + 68, camY);
|
||||||
MemoryUtil.memPutFloat(ptr + 72, camZ);
|
MemoryUtil.memPutFloat(ptr + 72, camZ);
|
||||||
|
|
|
@ -11,7 +11,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.jozufozu.flywheel.backend.Backend;
|
import com.jozufozu.flywheel.backend.Backend;
|
||||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry;
|
import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry;
|
||||||
import com.jozufozu.flywheel.util.ClientLevelExtension;
|
import com.jozufozu.flywheel.util.extension.ClientLevelExtension;
|
||||||
|
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
|
|
@ -43,7 +43,9 @@ public class LevelRendererMixin {
|
||||||
|
|
||||||
@Inject(at = @At("HEAD"), method = "renderLevel")
|
@Inject(at = @At("HEAD"), method = "renderLevel")
|
||||||
private void beginRender(PoseStack pPoseStack, float pPartialTick, long pFinishNanoTime, boolean pRenderBlockOutline, Camera pCamera, GameRenderer pGameRenderer, LightTexture pLightTexture, Matrix4f pProjectionMatrix, CallbackInfo ci) {
|
private void beginRender(PoseStack pPoseStack, float pPartialTick, long pFinishNanoTime, boolean pRenderBlockOutline, Camera pCamera, GameRenderer pGameRenderer, LightTexture pLightTexture, Matrix4f pProjectionMatrix, CallbackInfo ci) {
|
||||||
renderContext = new RenderContext((LevelRenderer) (Object) this, level, pPoseStack, RenderContext.createViewProjection(pPoseStack, pProjectionMatrix), pProjectionMatrix, renderBuffers, pCamera);
|
var viewProjection = RenderContext.createViewProjection(pPoseStack, pProjectionMatrix);
|
||||||
|
var culler = RenderContext.createCuller(pCamera, viewProjection);
|
||||||
|
renderContext = new RenderContext((LevelRenderer) (Object) this, level, pPoseStack, viewProjection, pProjectionMatrix, renderBuffers, pCamera, culler);
|
||||||
|
|
||||||
try (var restoreState = GlStateTracker.getRestoreState()) {
|
try (var restoreState = GlStateTracker.getRestoreState()) {
|
||||||
MinecraftForge.EVENT_BUS.post(new BeginFrameEvent(renderContext));
|
MinecraftForge.EVENT_BUS.post(new BeginFrameEvent(renderContext));
|
||||||
|
|
|
@ -8,7 +8,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.instancing.batching.DrawBuffer;
|
import com.jozufozu.flywheel.backend.instancing.batching.DrawBuffer;
|
||||||
import com.jozufozu.flywheel.util.RenderTypeExtension;
|
import com.jozufozu.flywheel.util.extension.RenderTypeExtension;
|
||||||
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,12 @@ import org.lwjgl.system.MemoryUtil;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.util.MatrixWrite;
|
import com.jozufozu.flywheel.util.extension.Matrix3fExtension;
|
||||||
|
import com.jozufozu.flywheel.util.extension.MatrixExtension;
|
||||||
import com.mojang.math.Matrix3f;
|
import com.mojang.math.Matrix3f;
|
||||||
|
|
||||||
@Mixin(Matrix3f.class)
|
@Mixin(Matrix3f.class)
|
||||||
public abstract class Matrix3fMixin implements MatrixWrite {
|
public abstract class Matrix3fMixin implements MatrixExtension, Matrix3fExtension {
|
||||||
|
|
||||||
@Shadow protected float m00;
|
@Shadow protected float m00;
|
||||||
@Shadow protected float m01;
|
@Shadow protected float m01;
|
||||||
|
@ -47,4 +48,9 @@ public abstract class Matrix3fMixin implements MatrixWrite {
|
||||||
buffer.putFloat(m12);
|
buffer.putFloat(m12);
|
||||||
buffer.putFloat(m22);
|
buffer.putFloat(m22);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public com.jozufozu.flywheel.util.joml.Matrix3f flywheel$store(com.jozufozu.flywheel.util.joml.Matrix3f matrix) {
|
||||||
|
return matrix.set(m00, m10, m20, m01, m11, m21, m02, m12, m22);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,12 @@ import org.lwjgl.system.MemoryUtil;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.util.MatrixWrite;
|
import com.jozufozu.flywheel.util.extension.Matrix4fExtension;
|
||||||
|
import com.jozufozu.flywheel.util.extension.MatrixExtension;
|
||||||
import com.mojang.math.Matrix4f;
|
import com.mojang.math.Matrix4f;
|
||||||
|
|
||||||
@Mixin(Matrix4f.class)
|
@Mixin(Matrix4f.class)
|
||||||
public abstract class Matrix4fMixin implements MatrixWrite {
|
public abstract class Matrix4fMixin implements MatrixExtension, Matrix4fExtension {
|
||||||
|
|
||||||
@Shadow protected float m00;
|
@Shadow protected float m00;
|
||||||
@Shadow protected float m01;
|
@Shadow protected float m01;
|
||||||
|
@ -68,4 +69,13 @@ public abstract class Matrix4fMixin implements MatrixWrite {
|
||||||
buf.putFloat(m23);
|
buf.putFloat(m23);
|
||||||
buf.putFloat(m33);
|
buf.putFloat(m33);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public com.jozufozu.flywheel.util.joml.Matrix4f flywheel$store(com.jozufozu.flywheel.util.joml.Matrix4f matrix) {
|
||||||
|
return matrix.set(
|
||||||
|
m00, m10, m20, m30,
|
||||||
|
m01, m11, m21, m31,
|
||||||
|
m02, m12, m22, m32,
|
||||||
|
m03, m13, m23, m33);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,10 @@ public class Lazy<T> implements Supplier<T> {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isInitialized() {
|
||||||
|
return value != null;
|
||||||
|
}
|
||||||
|
|
||||||
public <Q> Lazy<Q> lazyMap(Function<T, Q> func) {
|
public <Q> Lazy<Q> lazyMap(Function<T, Q> func) {
|
||||||
return new Lazy<>(() -> func.apply(get()));
|
return new Lazy<>(() -> func.apply(get()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package com.jozufozu.flywheel.util;
|
package com.jozufozu.flywheel.util.extension;
|
||||||
|
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.jozufozu.flywheel.util;
|
package com.jozufozu.flywheel.util.extension;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
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.Matrix3fMixin
|
||||||
* @see com.jozufozu.flywheel.mixin.matrix.Matrix4fMixin
|
* @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.
|
* 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);
|
void flywheel$write(ByteBuffer buf);
|
||||||
|
|
||||||
static void write(Matrix4f matrix, 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) {
|
static void writeUnsafe(Matrix4f matrix, long ptr) {
|
||||||
((MatrixWrite) (Object) matrix).flywheel$writeUnsafe(ptr);
|
((MatrixExtension) (Object) matrix).flywheel$writeUnsafe(ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.jozufozu.flywheel.util;
|
package com.jozufozu.flywheel.util.extension;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.instancing.batching.DrawBuffer;
|
import com.jozufozu.flywheel.backend.instancing.batching.DrawBuffer;
|
||||||
|
|
|
@ -23,6 +23,9 @@
|
||||||
*/
|
*/
|
||||||
package com.jozufozu.flywheel.util.joml;
|
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}.
|
* Efficiently performs frustum intersection tests by caching the frustum planes of an arbitrary transformation {@link Matrix4fc matrix}.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -950,4 +953,40 @@ public class FrustumIntersection {
|
||||||
return da >= 0.0f || db >= 0.0f;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,8 @@ import java.nio.FloatBuffer;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
|
|
||||||
|
import com.mojang.math.Quaternion;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Quaternion of 4 single-precision floats which can represent rotation and uniform scaling.
|
* 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;
|
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
|
* @return the first component of the vector part
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -18,6 +18,7 @@ import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
||||||
import com.jozufozu.flywheel.util.AnimationTickHolder;
|
import com.jozufozu.flywheel.util.AnimationTickHolder;
|
||||||
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;
|
||||||
|
import com.jozufozu.flywheel.util.joml.FrustumIntersection;
|
||||||
import com.jozufozu.flywheel.util.joml.Vector3f;
|
import com.jozufozu.flywheel.util.joml.Vector3f;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
@ -297,5 +298,10 @@ public class ExampleEffect implements Effect {
|
||||||
public boolean decreaseFramerateWithDistance() {
|
public boolean decreaseFramerateWithDistance() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkFrustum(FrustumIntersection frustum) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
out vec4 fragColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
fragColor = vec4(1.0, 1.0, 1.0, 0.2);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
Loading…
Reference in a new issue