diff --git a/src/main/java/com/jozufozu/flywheel/api/visualization/VisualEmbedding.java b/src/main/java/com/jozufozu/flywheel/api/visualization/VisualEmbedding.java
index fe75a0d43..6b84b53ba 100644
--- a/src/main/java/com/jozufozu/flywheel/api/visualization/VisualEmbedding.java
+++ b/src/main/java/com/jozufozu/flywheel/api/visualization/VisualEmbedding.java
@@ -5,6 +5,8 @@ import org.joml.Matrix4fc;
import com.jozufozu.flywheel.api.BackendImplemented;
+import net.minecraft.world.level.BlockAndTintGetter;
+
@BackendImplemented
public interface VisualEmbedding extends VisualizationContext {
/**
@@ -14,4 +16,36 @@ public interface VisualEmbedding extends VisualizationContext {
* @param normal The normal matrix.
*/
void transforms(Matrix4fc pose, Matrix3fc normal);
+
+ /**
+ * Collect light information from the given level for the given box.
+ *
+ *
Call this method on as many or as few boxes as you need to
+ * encompass all child visuals of this embedding.
+ *
+ * After this method is called, instances rendered from this
+ * embedding within the given box will be lit as if they were in
+ * the given level.
+ *
+ * @param level The level to collect light information from.
+ * @param minX The minimum x coordinate of the box.
+ * @param minY The minimum y coordinate of the box.
+ * @param minZ The minimum z coordinate of the box.
+ * @param sizeX The size of the box in the x direction.
+ * @param sizeY The size of the box in the y direction.
+ * @param sizeZ The size of the box in the z direction.
+ */
+ void light(BlockAndTintGetter level, int minX, int minY, int minZ, int sizeX, int sizeY, int sizeZ);
+
+ /**
+ * Reset any collected lighting information for the given box.
+ *
+ * @param minX The minimum x coordinate of the box.
+ * @param minY The minimum y coordinate of the box.
+ * @param minZ The minimum z coordinate of the box.
+ * @param sizeX The size of the box in the x direction.
+ * @param sizeY The size of the box in the y direction.
+ * @param sizeZ The size of the box in the z direction.
+ */
+ void invalidateLight(int minX, int minY, int minZ, int sizeX, int sizeY, int sizeZ);
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/Samplers.java b/src/main/java/com/jozufozu/flywheel/backend/Samplers.java
index f77dd99dd..05c14697f 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/Samplers.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/Samplers.java
@@ -8,4 +8,5 @@ public class Samplers {
public static final GlTextureUnit LIGHT = GlTextureUnit.T2;
public static final GlTextureUnit CRUMBLING = GlTextureUnit.T3;
public static final GlTextureUnit INSTANCE_BUFFER = GlTextureUnit.T4;
+ public static final GlTextureUnit EMBEDDED_LIGHT = GlTextureUnit.T5;
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/ContextShader.java b/src/main/java/com/jozufozu/flywheel/backend/compile/ContextShader.java
index 3df924cec..25be6c307 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/compile/ContextShader.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/compile/ContextShader.java
@@ -1,48 +1,40 @@
package com.jozufozu.flywheel.backend.compile;
-import java.util.Objects;
+import java.util.Locale;
import java.util.function.Consumer;
import org.jetbrains.annotations.Nullable;
+import com.jozufozu.flywheel.backend.Samplers;
+import com.jozufozu.flywheel.backend.compile.core.Compilation;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
-import net.minecraft.resources.ResourceLocation;
+public enum ContextShader {
+ DEFAULT(null, $ -> {
+ }),
+ CRUMBLING("_FLW_CRUMBLING", program -> program.setSamplerBinding("_flw_crumblingTex", Samplers.CRUMBLING)),
+ EMBEDDED("_FLW_EMBEDDED", program -> program.setSamplerBinding("_flw_lightVolume", Samplers.EMBEDDED_LIGHT));
-public record ContextShader(ResourceLocation vertexShader, ResourceLocation fragmentShader,
- Consumer onLink) {
- public static Builder builder() {
- return new Builder();
+ @Nullable
+ private final String define;
+ private final Consumer onLink;
+
+ ContextShader(@Nullable String define, Consumer onLink) {
+ this.define = define;
+ this.onLink = onLink;
}
- public static class Builder {
- @Nullable
- private ResourceLocation vertexShader;
- @Nullable
- private ResourceLocation fragmentShader;
- @Nullable
- private Consumer onLink;
+ public void onLink(GlProgram program) {
+ onLink.accept(program);
+ }
- public Builder vertexShader(ResourceLocation shader) {
- this.vertexShader = shader;
- return this;
+ public void onCompile(Compilation comp) {
+ if (define != null) {
+ comp.define(define);
}
+ }
- public Builder fragmentShader(ResourceLocation shader) {
- this.fragmentShader = shader;
- return this;
- }
-
- public Builder onLink(Consumer onLink) {
- this.onLink = onLink;
- return this;
- }
-
- public ContextShader build() {
- Objects.requireNonNull(vertexShader);
- Objects.requireNonNull(fragmentShader);
- Objects.requireNonNull(onLink);
- return new ContextShader(vertexShader, fragmentShader, onLink);
- }
+ public String nameLowerCase() {
+ return name().toLowerCase(Locale.ROOT);
}
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/ContextShaders.java b/src/main/java/com/jozufozu/flywheel/backend/compile/ContextShaders.java
deleted file mode 100644
index 37cce6b74..000000000
--- a/src/main/java/com/jozufozu/flywheel/backend/compile/ContextShaders.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.jozufozu.flywheel.backend.compile;
-
-import org.jetbrains.annotations.Nullable;
-
-import com.jozufozu.flywheel.Flywheel;
-import com.jozufozu.flywheel.api.internal.InternalFlywheelApi;
-import com.jozufozu.flywheel.api.registry.Registry;
-import com.jozufozu.flywheel.api.visualization.VisualEmbedding;
-import com.jozufozu.flywheel.backend.Samplers;
-
-public class ContextShaders {
- public static final Registry REGISTRY = InternalFlywheelApi.INSTANCE.createRegistry();
- public static final ContextShader DEFAULT = REGISTRY.registerAndGet(ContextShader.builder()
- .vertexShader(Flywheel.rl("internal/context/default.vert"))
- .fragmentShader(Flywheel.rl("internal/context/default.frag"))
- .onLink($ -> {
- })
- .build());
- public static final ContextShader CRUMBLING = REGISTRY.registerAndGet(ContextShader.builder()
- .vertexShader(Flywheel.rl("internal/context/crumbling.vert"))
- .fragmentShader(Flywheel.rl("internal/context/crumbling.frag"))
- .onLink(program -> program.setSamplerBinding("_flw_crumblingTex", Samplers.CRUMBLING))
- .build());
- public static final ContextShader EMBEDDED = REGISTRY.registerAndGet(ContextShader.builder()
- .vertexShader(Flywheel.rl("internal/context/embedded.vert"))
- .fragmentShader(Flywheel.rl("internal/context/embedded.frag"))
- .onLink($ -> {
- })
- .build());
-
- public static ContextShader forEmbedding(@Nullable VisualEmbedding level) {
- if (level == null) {
- return DEFAULT;
- } else {
- return EMBEDDED;
- }
- }
-}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/FlwPrograms.java b/src/main/java/com/jozufozu/flywheel/backend/compile/FlwPrograms.java
index de8e5b145..0fe34b95e 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/compile/FlwPrograms.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/compile/FlwPrograms.java
@@ -57,7 +57,7 @@ public final class FlwPrograms {
private static ImmutableList createPipelineKeys() {
ImmutableList.Builder builder = ImmutableList.builder();
- for (ContextShader contextShader : ContextShaders.REGISTRY) {
+ for (ContextShader contextShader : ContextShader.values()) {
for (InstanceType> instanceType : InstanceType.REGISTRY) {
builder.add(new PipelineProgramKey(instanceType, contextShader));
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/PipelineCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/compile/PipelineCompiler.java
index dd9589535..5a4cbdfe6 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/compile/PipelineCompiler.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/compile/PipelineCompiler.java
@@ -22,10 +22,12 @@ public class PipelineCompiler {
var instance = ResourceUtil.toDebugFileNameNoExtension(key.instanceType()
.vertexShader());
- var context = ResourceUtil.toDebugFileNameNoExtension(key.contextShader()
- .vertexShader());
+ var context = key.contextShader()
+ .nameLowerCase();
return "pipeline/" + pipeline.compilerMarker() + "/" + instance + "_" + context;
})
+ .onCompile((key, comp) -> key.contextShader()
+ .onCompile(comp))
.withResource(pipeline.vertexApiImpl())
.withResource(InternalVertex.LAYOUT_SHADER)
.withComponent(key -> pipeline.assembler()
@@ -33,23 +35,18 @@ public class PipelineCompiler {
.withComponents(vertexComponents)
.withResource(key -> key.instanceType()
.vertexShader())
- .withResource(key -> key.contextShader()
- .vertexShader())
.withResource(pipeline.vertexMain()))
.link(PIPELINE.shader(pipeline.glslVersion(), ShaderType.FRAGMENT)
.nameMapper(key -> {
- var instance = ResourceUtil.toDebugFileNameNoExtension(key.instanceType()
- .vertexShader());
-
- var context = ResourceUtil.toDebugFileNameNoExtension(key.contextShader()
- .fragmentShader());
- return "pipeline/" + pipeline.compilerMarker() + "/" + instance + "_" + context;
+ var context = key.contextShader()
+ .nameLowerCase();
+ return "pipeline/" + pipeline.compilerMarker() + "/" + context;
})
.enableExtension("GL_ARB_conservative_depth")
+ .onCompile((key, comp) -> key.contextShader()
+ .onCompile(comp))
.withResource(pipeline.fragmentApiImpl())
.withComponents(fragmentComponents)
- .withResource(key -> key.contextShader()
- .fragmentShader())
.withResource(pipeline.fragmentMain()))
.preLink((key, program) -> {
program.bindAttribLocation("_flw_a_pos", 0);
@@ -71,8 +68,7 @@ public class PipelineCompiler {
pipeline.onLink()
.accept(program);
key.contextShader()
- .onLink()
- .accept(program);
+ .onLink(program);
GlProgram.unbind();
})
diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/core/Compile.java b/src/main/java/com/jozufozu/flywheel/backend/compile/core/Compile.java
index a1a87ca28..83d723d11 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/compile/core/Compile.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/compile/core/Compile.java
@@ -106,7 +106,7 @@ public class Compile {
private final GlslVersion glslVersion;
private final ShaderType shaderType;
private final List> fetchers = new ArrayList<>();
- private Consumer compilationCallbacks = $ -> {
+ private BiConsumer compilationCallbacks = ($, $$) -> {
};
private Function nameMapper = Object::toString;
@@ -146,17 +146,17 @@ public class Compile {
return withResource($ -> resourceLocation);
}
- public ShaderCompiler onCompile(Consumer cb) {
+ public ShaderCompiler onCompile(BiConsumer cb) {
compilationCallbacks = compilationCallbacks.andThen(cb);
return this;
}
public ShaderCompiler define(String def, int value) {
- return onCompile(ctx -> ctx.define(def, String.valueOf(value)));
+ return onCompile(($, ctx) -> ctx.define(def, String.valueOf(value)));
}
public ShaderCompiler enableExtension(String extension) {
- return onCompile(ctx -> ctx.enableExtension(extension));
+ return onCompile(($, ctx) -> ctx.enableExtension(extension));
}
@Nullable
@@ -175,7 +175,8 @@ public class Compile {
return null;
}
- return compiler.compile(glslVersion, shaderType, nameMapper.apply(key), compilationCallbacks, components);
+ Consumer cb = ctx -> compilationCallbacks.accept(key, ctx);
+ return compiler.compile(glslVersion, shaderType, nameMapper.apply(key), cb, components);
}
}
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/core/ShaderCache.java b/src/main/java/com/jozufozu/flywheel/backend/compile/core/ShaderCache.java
index 3611efe00..3481a3170 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/compile/core/ShaderCache.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/compile/core/ShaderCache.java
@@ -25,7 +25,7 @@ public class ShaderCache {
@Nullable
public GlShader compile(GlslVersion glslVersion, ShaderType shaderType, String name, Consumer callback, List sourceComponents) {
- var key = new ShaderKey(glslVersion, shaderType, sourceComponents);
+ var key = new ShaderKey(glslVersion, shaderType, name);
var cached = inner.get(key);
if (cached != null) {
return cached.unwrap();
@@ -69,6 +69,6 @@ public class ShaderCache {
included.addAll(component.included());
}
- private record ShaderKey(GlslVersion glslVersion, ShaderType shaderType, List sourceComponents) {
+ private record ShaderKey(GlslVersion glslVersion, ShaderType shaderType, String name) {
}
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractEngine.java b/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractEngine.java
index 219b52f56..2d529517a 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractEngine.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractEngine.java
@@ -9,6 +9,8 @@ import com.jozufozu.flywheel.api.instance.InstancerProvider;
import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.visualization.VisualEmbedding;
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
+import com.jozufozu.flywheel.backend.engine.embed.EmbeddedEnvironment;
+import com.jozufozu.flywheel.backend.engine.embed.Environment;
import net.minecraft.client.Camera;
import net.minecraft.core.BlockPos;
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java
index ad0c6ac1f..84becc5bd 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java
@@ -7,6 +7,7 @@ import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.instance.Instancer;
+import com.jozufozu.flywheel.backend.engine.embed.Environment;
import com.jozufozu.flywheel.lib.util.AtomicBitset;
public abstract class AbstractInstancer implements Instancer {
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerKey.java b/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerKey.java
index ecb240dce..5c009c137 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerKey.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerKey.java
@@ -4,6 +4,7 @@ import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.model.Model;
+import com.jozufozu.flywheel.backend.engine.embed.Environment;
public record InstancerKey(Environment environment, InstanceType type, Model model,
RenderStage stage) {
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerProviderImpl.java b/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerProviderImpl.java
index e3894d308..d0aacd2a5 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerProviderImpl.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerProviderImpl.java
@@ -6,6 +6,7 @@ import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.instance.Instancer;
import com.jozufozu.flywheel.api.instance.InstancerProvider;
import com.jozufozu.flywheel.api.model.Model;
+import com.jozufozu.flywheel.backend.engine.embed.GlobalEnvironment;
public record InstancerProviderImpl(AbstractEngine engine, RenderStage renderStage) implements InstancerProvider {
@Override
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerStorage.java b/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerStorage.java
index 939cc42b5..a521aa49d 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerStorage.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerStorage.java
@@ -11,6 +11,10 @@ import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.instance.Instancer;
import com.jozufozu.flywheel.api.model.Model;
+import com.jozufozu.flywheel.backend.engine.embed.Environment;
+
+import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet;
+import it.unimi.dsi.fastutil.objects.ReferenceSet;
public abstract class InstancerStorage> {
/**
@@ -19,6 +23,7 @@ public abstract class InstancerStorage> {
* This map is populated as instancers are requested and contains both initialized and uninitialized instancers.
*/
protected final Map, N> instancers = new ConcurrentHashMap<>();
+ protected final ReferenceSet environments = new ReferenceLinkedOpenHashSet<>();
/**
* A list of instancers that have not yet been initialized.
*
@@ -32,6 +37,12 @@ public abstract class InstancerStorage> {
}
public void delete() {
+ // FIXME: The ownership of environments is a bit weird. Their resources are created and destroyed by the engine,
+ // but the engine doesn't own the things themselves. This makes it hard for the engine to know when to delete
+ // environments. For now, we just delete all environments when the engine is deleted, but this is not ideal.
+ environments.forEach(Environment::delete);
+ environments.clear();
+
instancers.clear();
initializationQueue.clear();
}
@@ -57,6 +68,8 @@ public abstract class InstancerStorage> {
private N createAndDeferInit(InstancerKey> key) {
var out = create(key);
+ environments.add(key.environment());
+
// Only queue the instancer for initialization if it has anything to render.
if (checkAndWarnEmptyModel(key.model())) {
// Thread safety: this method is called atomically from within computeIfAbsent,
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/EmbeddedEnvironment.java b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedEnvironment.java
similarity index 58%
rename from src/main/java/com/jozufozu/flywheel/backend/engine/EmbeddedEnvironment.java
rename to src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedEnvironment.java
index 9256dd0ab..cdcc68a3a 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/EmbeddedEnvironment.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedEnvironment.java
@@ -1,4 +1,4 @@
-package com.jozufozu.flywheel.backend.engine;
+package com.jozufozu.flywheel.backend.engine.embed;
import org.joml.Matrix3f;
import org.joml.Matrix3fc;
@@ -12,16 +12,21 @@ import com.jozufozu.flywheel.api.instance.Instancer;
import com.jozufozu.flywheel.api.instance.InstancerProvider;
import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.visualization.VisualEmbedding;
+import com.jozufozu.flywheel.backend.Samplers;
import com.jozufozu.flywheel.backend.compile.ContextShader;
-import com.jozufozu.flywheel.backend.compile.ContextShaders;
+import com.jozufozu.flywheel.backend.engine.AbstractEngine;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
import net.minecraft.core.Vec3i;
+import net.minecraft.world.level.BlockAndTintGetter;
public class EmbeddedEnvironment implements Environment, VisualEmbedding {
private final Matrix4f pose = new Matrix4f();
private final Matrix3f normal = new Matrix3f();
+ private final EmbeddedLightVolume lightVolume = new EmbeddedLightVolume();
+ private final EmbeddedLightTexture lightTexture = new EmbeddedLightTexture();
+
private final InstancerProvider instancerProvider;
private final AbstractEngine engine;
private final RenderStage renderStage;
@@ -45,15 +50,39 @@ public class EmbeddedEnvironment implements Environment, VisualEmbedding {
this.normal.set(normal);
}
+ @Override
+ public void light(BlockAndTintGetter level, int minX, int minY, int minZ, int sizeX, int sizeY, int sizeZ) {
+ lightVolume.collect(level, minX, minY, minZ, sizeX, sizeY, sizeZ);
+ }
+
+ @Override
+ public void invalidateLight(int minX, int minY, int minZ, int sizeX, int sizeY, int sizeZ) {
+ lightVolume.invalidate(minX, minY, minZ, sizeX, sizeY, sizeZ);
+ }
+
@Override
public ContextShader contextShader() {
- return ContextShaders.EMBEDDED;
+ return ContextShader.EMBEDDED;
}
@Override
public void setupDraw(GlProgram drawProgram) {
- drawProgram.setVec3("_flw_oneOverLightBoxSize", 1, 1, 1);
- drawProgram.setVec3("_flw_lightVolumeMin", 0, 0, 0);
+ if (!lightVolume.empty()) {
+ Samplers.EMBEDDED_LIGHT.makeActive();
+
+ lightTexture.bind();
+
+ lightTexture.ensureCapacity(lightVolume.sizeX, lightVolume.sizeY, lightVolume.sizeZ);
+
+ lightTexture.upload(lightVolume.ptr(), lightVolume.sizeX, lightVolume.sizeY, lightVolume.sizeZ);
+
+ float oneOverSizeX = 1f / (float) lightTexture.sizeX;
+ float oneOverSizeY = 1f / (float) lightTexture.sizeY;
+ float oneOverSizeZ = 1f / (float) lightTexture.sizeZ;
+
+ drawProgram.setVec3("_flw_oneOverLightBoxSize", oneOverSizeX, oneOverSizeY, oneOverSizeZ);
+ drawProgram.setVec3("_flw_lightVolumeMin", lightVolume.minX, lightVolume.minY, lightVolume.minZ);
+ }
drawProgram.setMat4("_flw_model", pose);
drawProgram.setMat3("_flw_normal", normal);
}
@@ -78,4 +107,10 @@ public class EmbeddedEnvironment implements Environment, VisualEmbedding {
public VisualEmbedding createEmbedding() {
return new EmbeddedEnvironment(engine, renderStage);
}
+
+ @Override
+ public void delete() {
+ lightVolume.delete();
+ lightTexture.delete();
+ }
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedLightTexture.java b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedLightTexture.java
new file mode 100644
index 000000000..4ea024d29
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedLightTexture.java
@@ -0,0 +1,88 @@
+package com.jozufozu.flywheel.backend.engine.embed;
+
+import static org.lwjgl.opengl.GL11.GL_LINEAR;
+import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER;
+import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER;
+import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S;
+import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T;
+import static org.lwjgl.opengl.GL11.GL_UNPACK_ALIGNMENT;
+import static org.lwjgl.opengl.GL11.GL_UNPACK_ROW_LENGTH;
+import static org.lwjgl.opengl.GL11.GL_UNPACK_SKIP_PIXELS;
+import static org.lwjgl.opengl.GL11.GL_UNPACK_SKIP_ROWS;
+import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
+import static org.lwjgl.opengl.GL11.glPixelStorei;
+import static org.lwjgl.opengl.GL11.glTexParameteri;
+import static org.lwjgl.opengl.GL12.GL_TEXTURE_3D;
+import static org.lwjgl.opengl.GL12.GL_TEXTURE_WRAP_R;
+import static org.lwjgl.opengl.GL12.GL_UNPACK_IMAGE_HEIGHT;
+import static org.lwjgl.opengl.GL12.GL_UNPACK_SKIP_IMAGES;
+import static org.lwjgl.opengl.GL12.glTexImage3D;
+import static org.lwjgl.opengl.GL12.glTexSubImage3D;
+import static org.lwjgl.opengl.GL14.GL_MIRRORED_REPEAT;
+
+import org.jetbrains.annotations.Nullable;
+import org.lwjgl.opengl.GL30;
+
+import com.jozufozu.flywheel.backend.gl.GlTexture;
+
+import net.minecraft.util.Mth;
+
+public class EmbeddedLightTexture {
+ @Nullable
+ private GlTexture texture;
+
+ public int sizeX;
+ public int sizeY;
+ public int sizeZ;
+
+ public void bind() {
+
+ texture().bind();
+ }
+
+ private GlTexture texture() {
+ if (texture == null) {
+ texture = new GlTexture(GL_TEXTURE_3D);
+ }
+ return texture;
+ }
+
+ public void ensureCapacity(int sizeX, int sizeY, int sizeZ) {
+ sizeX = Mth.smallestEncompassingPowerOfTwo(sizeX);
+ sizeY = Mth.smallestEncompassingPowerOfTwo(sizeY);
+ sizeZ = Mth.smallestEncompassingPowerOfTwo(sizeZ);
+
+ if (sizeX > this.sizeX || sizeY > this.sizeY || sizeZ > this.sizeZ) {
+ this.sizeX = sizeX;
+ this.sizeY = sizeY;
+ this.sizeZ = sizeZ;
+
+ glTexImage3D(GL_TEXTURE_3D, 0, GL30.GL_RG8, sizeX, sizeY, sizeZ, 0, GL30.GL_RG, GL_UNSIGNED_BYTE, 0);
+
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
+ }
+ }
+
+ public void upload(long ptr, int sizeX, int sizeY, int sizeZ) {
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
+ glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, (int) EmbeddedLightVolume.STRIDE);
+
+ glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, sizeX, sizeY, sizeZ, GL30.GL_RG, GL_UNSIGNED_BYTE, ptr);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4 is the default
+ }
+
+ public void delete() {
+ if (texture != null) {
+ texture.delete();
+ }
+ }
+}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedLightVolume.java b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedLightVolume.java
new file mode 100644
index 000000000..521af1984
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/EmbeddedLightVolume.java
@@ -0,0 +1,147 @@
+package com.jozufozu.flywheel.backend.engine.embed;
+
+import org.jetbrains.annotations.Nullable;
+import org.lwjgl.system.MemoryUtil;
+
+import com.jozufozu.flywheel.lib.memory.MemoryBlock;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.BlockAndTintGetter;
+import net.minecraft.world.level.LightLayer;
+
+public class EmbeddedLightVolume {
+ public static final long STRIDE = Short.BYTES;
+ public int minX;
+ public int minY;
+ public int minZ;
+ public int sizeX;
+ public int sizeY;
+ public int sizeZ;
+ private final BlockPos.MutableBlockPos scratchPos = new BlockPos.MutableBlockPos();
+
+ @Nullable
+ protected MemoryBlock block;
+ protected boolean dirty;
+
+ public boolean empty() {
+ return block == null;
+ }
+
+ public void collect(BlockAndTintGetter level, int minX, int minY, int minZ, int sizeX, int sizeY, int sizeZ) {
+ maybeExpandForBox(minX, minY, minZ, sizeX, sizeY, sizeZ);
+
+ for (int z = minZ; z < minZ + sizeZ; z++) {
+ for (int y = minY; y < minY + sizeY; y++) {
+ for (int x = minX; x < minX + sizeX; x++) {
+ paintLight(level, x, y, z);
+ }
+ }
+ }
+
+ markDirty();
+ }
+
+ public void invalidate(int minX, int minY, int minZ, int sizeX, int sizeY, int sizeZ) {
+ // TODO: shrink the volume
+ }
+
+ private void paintLight(BlockAndTintGetter level, int x, int y, int z) {
+ scratchPos.set(x, y, z);
+
+ int block = level.getBrightness(LightLayer.BLOCK, scratchPos);
+ int sky = level.getBrightness(LightLayer.SKY, scratchPos);
+
+ long ptr = worldPosToPtr(x, y, z);
+ MemoryUtil.memPutShort(ptr, (short) ((block << 4) | sky << 12));
+ }
+
+ private void maybeExpandForBox(int minX, int minY, int minZ, int sizeX, int sizeY, int sizeZ) {
+ if (block == null) {
+ this.minX = minX;
+ this.minY = minY;
+ this.minZ = minZ;
+ this.sizeX = sizeX;
+ this.sizeY = sizeY;
+ this.sizeZ = sizeZ;
+
+ int volume = sizeX * sizeY * sizeZ;
+
+ block = MemoryBlock.malloc(volume * STRIDE);
+ block.clear();
+ return;
+ }
+
+ int newMinX = Math.min(this.minX, minX);
+ int newMinY = Math.min(this.minY, minY);
+ int newMinZ = Math.min(this.minZ, minZ);
+
+ int newSizeX = Math.max(this.minX + this.sizeX, minX + sizeX) - newMinX;
+ int newSizeY = Math.max(this.minY + this.sizeY, minY + sizeY) - newMinY;
+ int newSizeZ = Math.max(this.minZ + this.sizeZ, minZ + sizeZ) - newMinZ;
+
+ if (newMinX == this.minX && newMinY == this.minY && newMinZ == this.minZ && newSizeX == this.sizeX && newSizeY == this.sizeY && newSizeZ == this.sizeZ) {
+ return;
+ }
+
+ int newVolume = newSizeX * newSizeY * newSizeZ;
+
+ MemoryBlock newBlock = MemoryBlock.malloc(newVolume * STRIDE);
+ newBlock.clear();
+
+ int xOff = newMinX - this.minX;
+ int yOff = newMinY - this.minY;
+ int zOff = newMinZ - this.minZ;
+
+ for (int z = 0; z < this.sizeZ; z++) {
+ for (int y = 0; y < this.sizeY; y++) {
+ for (int x = 0; x < this.sizeX; x++) {
+ long oldPtr = boxPosToPtr(x, y, z);
+ long newPtr = newBlock.ptr() + x + xOff + (newSizeX * (y + yOff + (z + zOff) * newSizeY)) * STRIDE;
+
+ MemoryUtil.memPutShort(newPtr, MemoryUtil.memGetShort(oldPtr));
+ }
+ }
+ }
+
+ this.minX = newMinX;
+ this.minY = newMinY;
+ this.minZ = newMinZ;
+ this.sizeX = newSizeX;
+ this.sizeY = newSizeY;
+ this.sizeZ = newSizeZ;
+
+ block.free();
+ block = newBlock;
+ }
+
+ protected long worldPosToPtr(int x, int y, int z) {
+ return block.ptr() + worldPosToPtrOffset(x, y, z);
+ }
+
+ protected long boxPosToPtr(int x, int y, int z) {
+ return block.ptr() + boxPosToPtrOffset(x, y, z);
+ }
+
+ protected long worldPosToPtrOffset(int x, int y, int z) {
+ return boxPosToPtrOffset(x - minX, y - minY, z - minZ);
+ }
+
+ protected long boxPosToPtrOffset(int x, int y, int z) {
+ return (x + sizeX * (y + z * sizeY)) * STRIDE;
+ }
+
+ public void delete() {
+ if (block != null) {
+ block.free();
+ block = null;
+ }
+ }
+
+ protected void markDirty() {
+ this.dirty = true;
+ }
+
+ public long ptr() {
+ return block.ptr();
+ }
+}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/Environment.java b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/Environment.java
similarity index 79%
rename from src/main/java/com/jozufozu/flywheel/backend/engine/Environment.java
rename to src/main/java/com/jozufozu/flywheel/backend/engine/embed/Environment.java
index 6b3614e6e..e139ac234 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/Environment.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/Environment.java
@@ -1,4 +1,4 @@
-package com.jozufozu.flywheel.backend.engine;
+package com.jozufozu.flywheel.backend.engine.embed;
import com.jozufozu.flywheel.backend.compile.ContextShader;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
@@ -9,4 +9,6 @@ public interface Environment {
void setupDraw(GlProgram drawProgram);
void setupCull(GlProgram cullProgram);
+
+ void delete();
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/GlobalEnvironment.java b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/GlobalEnvironment.java
similarity index 78%
rename from src/main/java/com/jozufozu/flywheel/backend/engine/GlobalEnvironment.java
rename to src/main/java/com/jozufozu/flywheel/backend/engine/embed/GlobalEnvironment.java
index f1c909bcd..ff29e474d 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/GlobalEnvironment.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/embed/GlobalEnvironment.java
@@ -1,7 +1,6 @@
-package com.jozufozu.flywheel.backend.engine;
+package com.jozufozu.flywheel.backend.engine.embed;
import com.jozufozu.flywheel.backend.compile.ContextShader;
-import com.jozufozu.flywheel.backend.compile.ContextShaders;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
public class GlobalEnvironment implements Environment {
@@ -12,7 +11,7 @@ public class GlobalEnvironment implements Environment {
@Override
public ContextShader contextShader() {
- return ContextShaders.DEFAULT;
+ return ContextShader.DEFAULT;
}
@Override
@@ -24,4 +23,9 @@ public class GlobalEnvironment implements Environment {
public void setupCull(GlProgram cullProgram) {
cullProgram.setBool("_flw_useEmbeddedModel", false);
}
+
+ @Override
+ public void delete() {
+
+ }
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectCullingGroup.java b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectCullingGroup.java
index 8faec98da..f524a2219 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectCullingGroup.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectCullingGroup.java
@@ -23,9 +23,9 @@ import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.backend.compile.ContextShader;
import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
-import com.jozufozu.flywheel.backend.engine.Environment;
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
import com.jozufozu.flywheel.backend.engine.MeshPool;
+import com.jozufozu.flywheel.backend.engine.embed.Environment;
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
import com.jozufozu.flywheel.backend.gl.Driver;
import com.jozufozu.flywheel.backend.gl.GlCompat;
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectDrawManager.java b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectDrawManager.java
index 2f5861647..5b760f93d 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectDrawManager.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectDrawManager.java
@@ -16,16 +16,16 @@ import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.backend.Samplers;
-import com.jozufozu.flywheel.backend.compile.ContextShaders;
+import com.jozufozu.flywheel.backend.compile.ContextShader;
import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
import com.jozufozu.flywheel.backend.engine.CommonCrumbling;
-import com.jozufozu.flywheel.backend.engine.Environment;
import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl;
import com.jozufozu.flywheel.backend.engine.InstancerKey;
import com.jozufozu.flywheel.backend.engine.InstancerStorage;
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
import com.jozufozu.flywheel.backend.engine.MeshPool;
import com.jozufozu.flywheel.backend.engine.TextureBinder;
+import com.jozufozu.flywheel.backend.engine.embed.Environment;
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
import com.jozufozu.flywheel.backend.gl.array.GlVertexArray;
@@ -164,7 +164,7 @@ public class IndirectDrawManager extends InstancerStorage>
// Set up the crumbling program buffers. Nothing changes here between draws.
var program = cullingGroups.get(instanceTypeEntry.getKey())
- .bindWithContextShader(ContextShaders.CRUMBLING);
+ .bindWithContextShader(ContextShader.CRUMBLING);
program.setSamplerBinding("crumblingTex", Samplers.CRUMBLING);
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectInstancer.java
index 88362d85e..f2e92530a 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectInstancer.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectInstancer.java
@@ -11,7 +11,7 @@ import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.instance.InstanceWriter;
import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
-import com.jozufozu.flywheel.backend.engine.Environment;
+import com.jozufozu.flywheel.backend.engine.embed.Environment;
public class IndirectInstancer extends AbstractInstancer {
private final long objectStride;
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedDrawManager.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedDrawManager.java
index 04b640ecc..a2e029fc0 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedDrawManager.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedDrawManager.java
@@ -20,7 +20,7 @@ import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.backend.Samplers;
import com.jozufozu.flywheel.backend.ShaderIndices;
-import com.jozufozu.flywheel.backend.compile.ContextShaders;
+import com.jozufozu.flywheel.backend.compile.ContextShader;
import com.jozufozu.flywheel.backend.compile.InstancingPrograms;
import com.jozufozu.flywheel.backend.engine.CommonCrumbling;
import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl;
@@ -203,7 +203,7 @@ public class InstancedDrawManager extends InstancerStorage
CommonCrumbling.applyCrumblingProperties(crumblingMaterial, shader.material());
- var program = programs.get(shader.instanceType(), ContextShaders.CRUMBLING);
+ var program = programs.get(shader.instanceType(), ContextShader.CRUMBLING);
program.bind();
uploadMaterialUniform(program, crumblingMaterial);
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedInstancer.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedInstancer.java
index 85684ed92..6ff46fe46 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedInstancer.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedInstancer.java
@@ -9,7 +9,7 @@ import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.instance.InstanceWriter;
import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
-import com.jozufozu.flywheel.backend.engine.Environment;
+import com.jozufozu.flywheel.backend.engine.embed.Environment;
import com.jozufozu.flywheel.backend.gl.TextureBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferUsage;
diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/ShaderState.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/ShaderState.java
index 420fb7005..185f1688e 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/ShaderState.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/ShaderState.java
@@ -2,7 +2,7 @@ package com.jozufozu.flywheel.backend.engine.instancing;
import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.material.Material;
-import com.jozufozu.flywheel.backend.engine.Environment;
+import com.jozufozu.flywheel.backend.engine.embed.Environment;
public record ShaderState(Material material, InstanceType> instanceType, Environment environment) {
}
diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/GlTexture.java b/src/main/java/com/jozufozu/flywheel/backend/gl/GlTexture.java
index 901df99af..4a05ba15f 100644
--- a/src/main/java/com/jozufozu/flywheel/backend/gl/GlTexture.java
+++ b/src/main/java/com/jozufozu/flywheel/backend/gl/GlTexture.java
@@ -23,7 +23,4 @@ public class GlTexture extends GlObject {
GL20.glBindTexture(textureType, 0);
}
- public void setParameteri(int parameter, int value) {
- GL20.glTexParameteri(textureType, parameter, value);
- }
}
diff --git a/src/main/java/com/jozufozu/flywheel/config/DebugMode.java b/src/main/java/com/jozufozu/flywheel/config/DebugMode.java
index b021a2e23..135a577b2 100644
--- a/src/main/java/com/jozufozu/flywheel/config/DebugMode.java
+++ b/src/main/java/com/jozufozu/flywheel/config/DebugMode.java
@@ -6,4 +6,5 @@ public enum DebugMode {
INSTANCE_ID,
LIGHT,
OVERLAY,
+ LIGHT_VOLUME,
}
diff --git a/src/main/java/com/jozufozu/flywheel/lib/light/GPULightVolume.java b/src/main/java/com/jozufozu/flywheel/lib/light/GPULightVolume.java
deleted file mode 100644
index 3e18aa377..000000000
--- a/src/main/java/com/jozufozu/flywheel/lib/light/GPULightVolume.java
+++ /dev/null
@@ -1,133 +0,0 @@
-package com.jozufozu.flywheel.lib.light;
-
-import static org.lwjgl.opengl.GL11.GL_LINEAR;
-import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER;
-import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER;
-import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S;
-import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T;
-import static org.lwjgl.opengl.GL11.GL_UNPACK_ALIGNMENT;
-import static org.lwjgl.opengl.GL11.GL_UNPACK_ROW_LENGTH;
-import static org.lwjgl.opengl.GL11.GL_UNPACK_SKIP_PIXELS;
-import static org.lwjgl.opengl.GL11.GL_UNPACK_SKIP_ROWS;
-import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
-import static org.lwjgl.opengl.GL11.glPixelStorei;
-import static org.lwjgl.opengl.GL12.GL_TEXTURE_3D;
-import static org.lwjgl.opengl.GL12.GL_TEXTURE_WRAP_R;
-import static org.lwjgl.opengl.GL12.GL_UNPACK_IMAGE_HEIGHT;
-import static org.lwjgl.opengl.GL12.GL_UNPACK_SKIP_IMAGES;
-import static org.lwjgl.opengl.GL12.glTexImage3D;
-import static org.lwjgl.opengl.GL12.glTexSubImage3D;
-import static org.lwjgl.opengl.GL14.GL_MIRRORED_REPEAT;
-
-import org.lwjgl.opengl.GL30;
-
-import com.jozufozu.flywheel.backend.gl.GlTexture;
-import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
-import com.jozufozu.flywheel.lib.box.Box;
-import com.jozufozu.flywheel.lib.box.MutableBox;
-
-import net.minecraft.world.level.BlockAndTintGetter;
-
-public class GPULightVolume extends LightVolume {
-
- protected final MutableBox sampleVolume = new MutableBox();
- private final GlTexture glTexture;
-
- private final GlTextureUnit textureUnit = GlTextureUnit.T4;
- protected boolean bufferDirty;
-
- public GPULightVolume(BlockAndTintGetter level, Box sampleVolume) {
- super(level, sampleVolume);
- this.sampleVolume.assign(sampleVolume);
-
- glTexture = new GlTexture(GL_TEXTURE_3D);
-
- GlTextureUnit oldState = GlTextureUnit.getActive();
-
- // allocate space for the texture
- textureUnit.makeActive();
- glTexture.bind();
-
- int sizeX = box.sizeX();
- int sizeY = box.sizeY();
- int sizeZ = box.sizeZ();
- glTexImage3D(GL_TEXTURE_3D, 0, GL30.GL_RG8, sizeX, sizeY, sizeZ, 0, GL30.GL_RG, GL_UNSIGNED_BYTE, 0);
-
- glTexture.setParameteri(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexture.setParameteri(GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexture.setParameteri(GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
- glTexture.setParameteri(GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
- glTexture.setParameteri(GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
-
- glTexture.unbind();
- oldState.makeActive();
- }
-
- @Override
- protected void setBox(Box box) {
- this.box.assign(box);
- this.box.nextPowerOf2Centered();
- // called during super ctor
- if (sampleVolume != null) this.sampleVolume.assign(box);
- }
-
- public void bind() {
- // just in case something goes wrong, or we accidentally call this before this volume is properly disposed of.
- if (lightData == null || lightData.size() == 0) return;
-
- textureUnit.makeActive();
- glTexture.bind();
-
- uploadTexture();
- }
-
- private void uploadTexture() {
- if (bufferDirty) {
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
- glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
- glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
- glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
- glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 2); // we use 2 bytes per texel
- int sizeX = box.sizeX();
- int sizeY = box.sizeY();
- int sizeZ = box.sizeZ();
-
- glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, sizeX, sizeY, sizeZ, GL30.GL_RG, GL_UNSIGNED_BYTE, lightData.ptr());
-
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4 is the default
- bufferDirty = false;
- }
- }
-
- public void unbind() {
- glTexture.unbind();
- }
-
- @Override
- public void delete() {
- super.delete();
- glTexture.delete();
- }
-
- public void move(Box newSampleVolume) {
- if (lightData == null) return;
-
- if (box.contains(newSampleVolume)) {
- sampleVolume.assign(newSampleVolume);
- initialize();
- } else {
- super.move(newSampleVolume);
- }
- }
-
- @Override
- public Box getVolume() {
- return sampleVolume;
- }
-
- @Override
- protected void markDirty() {
- this.bufferDirty = true;
- }
-}
diff --git a/src/main/resources/assets/flywheel/flywheel/internal/common.frag b/src/main/resources/assets/flywheel/flywheel/internal/common.frag
index 98d510611..63d08e0cd 100644
--- a/src/main/resources/assets/flywheel/flywheel/internal/common.frag
+++ b/src/main/resources/assets/flywheel/flywheel/internal/common.frag
@@ -6,19 +6,42 @@
layout (depth_greater) out float gl_FragDepth;
#endif
-out vec4 _flw_outputColor;
+#ifdef _FLW_CRUMBLING
+uniform sampler2D _flw_crumblingTex;
+
+in vec2 _flw_crumblingTexCoord;
+#endif
+
+#ifdef _FLW_EMBEDDED
+uniform sampler3D _flw_lightVolume;
+
+in vec3 _flw_lightVolumeCoord;
+
+#endif
in vec4 _flw_debugColor;
+out vec4 _flw_outputColor;
+
void _flw_main() {
flw_sampleColor = texture(flw_diffuseTex, flw_vertexTexCoord);
flw_fragColor = flw_vertexColor * flw_sampleColor;
flw_fragOverlay = flw_vertexOverlay;
flw_fragLight = flw_vertexLight;
- flw_beginFragment();
+ #ifdef _FLW_EMBEDDED
+ flw_fragLight = max(flw_fragLight, texture(_flw_lightVolume, _flw_lightVolumeCoord).rg);
+ #endif
+
flw_materialFragment();
- flw_endFragment();
+
+ #ifdef _FLW_CRUMBLING
+ vec4 crumblingSampleColor = texture(_flw_crumblingTex, _flw_crumblingTexCoord);
+
+ // Make the crumbling overlay transparent when the fragment color after the material shader is transparent.
+ flw_fragColor.rgb = crumblingSampleColor.rgb;
+ flw_fragColor.a *= crumblingSampleColor.a;
+ #endif
vec4 color = flw_fragColor;
diff --git a/src/main/resources/assets/flywheel/flywheel/internal/common.vert b/src/main/resources/assets/flywheel/flywheel/internal/common.vert
index d24e3e33c..21d49d78d 100644
--- a/src/main/resources/assets/flywheel/flywheel/internal/common.vert
+++ b/src/main/resources/assets/flywheel/flywheel/internal/common.vert
@@ -23,12 +23,97 @@ vec4 _flw_id2Color(in uint id) {
out vec4 _flw_debugColor;
+#ifdef _FLW_CRUMBLING
+out vec2 _flw_crumblingTexCoord;
+
+const int DOWN = 0;
+const int UP = 1;
+const int NORTH = 2;
+const int SOUTH = 3;
+const int WEST = 4;
+const int EAST = 5;
+
+// based on net.minecraftforge.client.ForgeHooksClient.getNearestStable
+int getNearestFacing(vec3 normal) {
+ float maxAlignment = -2;
+ int face = 2;
+
+ // Calculate the alignment of the normal vector with each axis.
+ // Note that `-dot(normal, axis) == dot(normal, -axis)`.
+ vec3 alignment = vec3(
+ dot(normal, vec3(1., 0., 0.)),
+ dot(normal, vec3(0., 1., 0.)),
+ dot(normal, vec3(0., 0., 1.))
+ );
+
+ if (-alignment.y > maxAlignment) {
+ maxAlignment = -alignment.y;
+ face = DOWN;
+ }
+ if (alignment.y > maxAlignment) {
+ maxAlignment = alignment.y;
+ face = UP;
+ }
+ if (-alignment.z > maxAlignment) {
+ maxAlignment = -alignment.z;
+ face = NORTH;
+ }
+ if (alignment.z > maxAlignment) {
+ maxAlignment = alignment.z;
+ face = SOUTH;
+ }
+ if (-alignment.x > maxAlignment) {
+ maxAlignment = -alignment.x;
+ face = WEST;
+ }
+ if (alignment.x > maxAlignment) {
+ maxAlignment = alignment.x;
+ face = EAST;
+ }
+
+ return face;
+}
+
+vec2 getCrumblingTexCoord() {
+ switch (getNearestFacing(flw_vertexNormal)) {
+ case DOWN: return vec2(flw_vertexPos.x, -flw_vertexPos.z);
+ case UP: return vec2(flw_vertexPos.x, flw_vertexPos.z);
+ case NORTH: return vec2(-flw_vertexPos.x, -flw_vertexPos.y);
+ case SOUTH: return vec2(flw_vertexPos.x, -flw_vertexPos.y);
+ case WEST: return vec2(-flw_vertexPos.z, -flw_vertexPos.y);
+ case EAST: return vec2(flw_vertexPos.z, -flw_vertexPos.y);
+ }
+
+ // default to north
+ return vec2(-flw_vertexPos.x, -flw_vertexPos.y);
+}
+#endif
+
+#ifdef _FLW_EMBEDDED
+uniform vec3 _flw_oneOverLightBoxSize;
+uniform vec3 _flw_lightVolumeMin;
+uniform mat4 _flw_model;
+uniform mat3 _flw_normal;
+
+out vec3 _flw_lightVolumeCoord;
+#endif
+
+
void _flw_main(in FlwInstance instance, in uint stableInstanceID) {
_flw_layoutVertex();
- flw_beginVertex();
flw_instanceVertex(instance);
flw_materialVertex();
- flw_endVertex();
+
+ #ifdef _FLW_CRUMBLING
+ _flw_crumblingTexCoord = getCrumblingTexCoord();
+ #endif
+
+ #ifdef _FLW_EMBEDDED
+ flw_vertexPos = _flw_model * flw_vertexPos;
+ flw_vertexNormal = _flw_normal * flw_vertexNormal;
+
+ _flw_lightVolumeCoord = (flw_vertexPos.xyz - _flw_lightVolumeMin) * _flw_oneOverLightBoxSize;
+ #endif
flw_vertexNormal = normalize(flw_vertexNormal);
@@ -52,5 +137,10 @@ void _flw_main(in FlwInstance instance, in uint stableInstanceID) {
case 4u:
_flw_debugColor = vec4(flw_vertexOverlay / 16., 0., 1.);
break;
+ #ifdef _FLW_LIGHT_VOLUME
+ case 5u:
+ _flw_debugColor = vec4(_flw_lightVolumeCoord, 1.);
+ break;
+ #endif
}
}
diff --git a/src/main/resources/assets/flywheel/flywheel/internal/context/crumbling.frag b/src/main/resources/assets/flywheel/flywheel/internal/context/crumbling.frag
deleted file mode 100644
index a722816bb..000000000
--- a/src/main/resources/assets/flywheel/flywheel/internal/context/crumbling.frag
+++ /dev/null
@@ -1,16 +0,0 @@
-uniform sampler2D _flw_crumblingTex;
-
-in vec2 crumblingTexCoord;
-
-vec4 crumblingSampleColor;
-
-void flw_beginFragment() {
-}
-
-void flw_endFragment() {
- crumblingSampleColor = texture(_flw_crumblingTex, crumblingTexCoord);
-
- // Make the crumbling overlay transparent when the fragment color after the material shader is transparent.
- flw_fragColor.rgb = crumblingSampleColor.rgb;
- flw_fragColor.a *= crumblingSampleColor.a;
-}
diff --git a/src/main/resources/assets/flywheel/flywheel/internal/context/crumbling.vert b/src/main/resources/assets/flywheel/flywheel/internal/context/crumbling.vert
deleted file mode 100644
index d765f4ee2..000000000
--- a/src/main/resources/assets/flywheel/flywheel/internal/context/crumbling.vert
+++ /dev/null
@@ -1,70 +0,0 @@
-out vec2 crumblingTexCoord;
-
-const int DOWN = 0;
-const int UP = 1;
-const int NORTH = 2;
-const int SOUTH = 3;
-const int WEST = 4;
-const int EAST = 5;
-
-// based on net.minecraftforge.client.ForgeHooksClient.getNearestStable
-int getNearestFacing(vec3 normal) {
- float maxAlignment = -2;
- int face = 2;
-
- // Calculate the alignment of the normal vector with each axis.
- // Note that `-dot(normal, axis) == dot(normal, -axis)`.
- vec3 alignment = vec3(
- dot(normal, vec3(1., 0., 0.)),
- dot(normal, vec3(0., 1., 0.)),
- dot(normal, vec3(0., 0., 1.))
- );
-
- if (-alignment.y > maxAlignment) {
- maxAlignment = -alignment.y;
- face = DOWN;
- }
- if (alignment.y > maxAlignment) {
- maxAlignment = alignment.y;
- face = UP;
- }
- if (-alignment.z > maxAlignment) {
- maxAlignment = -alignment.z;
- face = NORTH;
- }
- if (alignment.z > maxAlignment) {
- maxAlignment = alignment.z;
- face = SOUTH;
- }
- if (-alignment.x > maxAlignment) {
- maxAlignment = -alignment.x;
- face = WEST;
- }
- if (alignment.x > maxAlignment) {
- maxAlignment = alignment.x;
- face = EAST;
- }
-
- return face;
-}
-
-vec2 getCrumblingTexCoord() {
- switch (getNearestFacing(flw_vertexNormal)) {
- case DOWN: return vec2(flw_vertexPos.x, -flw_vertexPos.z);
- case UP: return vec2(flw_vertexPos.x, flw_vertexPos.z);
- case NORTH: return vec2(-flw_vertexPos.x, -flw_vertexPos.y);
- case SOUTH: return vec2(flw_vertexPos.x, -flw_vertexPos.y);
- case WEST: return vec2(-flw_vertexPos.z, -flw_vertexPos.y);
- case EAST: return vec2(flw_vertexPos.z, -flw_vertexPos.y);
- }
-
- // default to north
- return vec2(-flw_vertexPos.x, -flw_vertexPos.y);
-}
-
-void flw_beginVertex() {
-}
-
-void flw_endVertex() {
- crumblingTexCoord = getCrumblingTexCoord();
-}
diff --git a/src/main/resources/assets/flywheel/flywheel/internal/context/default.frag b/src/main/resources/assets/flywheel/flywheel/internal/context/default.frag
deleted file mode 100644
index d5d083a2a..000000000
--- a/src/main/resources/assets/flywheel/flywheel/internal/context/default.frag
+++ /dev/null
@@ -1,5 +0,0 @@
-void flw_beginFragment() {
-}
-
-void flw_endFragment() {
-}
diff --git a/src/main/resources/assets/flywheel/flywheel/internal/context/default.vert b/src/main/resources/assets/flywheel/flywheel/internal/context/default.vert
deleted file mode 100644
index 56efd2eae..000000000
--- a/src/main/resources/assets/flywheel/flywheel/internal/context/default.vert
+++ /dev/null
@@ -1,5 +0,0 @@
-void flw_beginVertex() {
-}
-
-void flw_endVertex() {
-}
diff --git a/src/main/resources/assets/flywheel/flywheel/internal/context/embedded.frag b/src/main/resources/assets/flywheel/flywheel/internal/context/embedded.frag
deleted file mode 100644
index 901805508..000000000
--- a/src/main/resources/assets/flywheel/flywheel/internal/context/embedded.frag
+++ /dev/null
@@ -1,10 +0,0 @@
-uniform sampler3D _flw_lightVolume;
-
-in vec3 _flw_lightVolumeCoord;
-
-void flw_beginFragment() {
- flw_fragLight = max(flw_fragLight, texture(_flw_lightVolume, _flw_lightVolumeCoord).rg);
-}
-
-void flw_endFragment() {
-}
diff --git a/src/main/resources/assets/flywheel/flywheel/internal/context/embedded.vert b/src/main/resources/assets/flywheel/flywheel/internal/context/embedded.vert
deleted file mode 100644
index 6b51f4444..000000000
--- a/src/main/resources/assets/flywheel/flywheel/internal/context/embedded.vert
+++ /dev/null
@@ -1,16 +0,0 @@
-uniform vec3 _flw_oneOverLightBoxSize;
-uniform vec3 _flw_lightVolumeMin;
-uniform mat4 _flw_model;
-uniform mat3 _flw_normal;
-
-out vec3 _flw_lightVolumeCoord;
-
-void flw_beginVertex() {
-}
-
-void flw_endVertex() {
- _flw_lightVolumeCoord = (flw_vertexPos.xyz - _flw_lightVolumeMin) * _flw_oneOverLightBoxSize;
-
- flw_vertexPos = _flw_model * flw_vertexPos;
- flw_vertexNormal = _flw_normal * flw_vertexNormal;
-}