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; -}