diff --git a/src/main/java/com/jozufozu/flywheel/Flywheel.java b/src/main/java/com/jozufozu/flywheel/Flywheel.java index 10ff45ee9..891d1538a 100644 --- a/src/main/java/com/jozufozu/flywheel/Flywheel.java +++ b/src/main/java/com/jozufozu/flywheel/Flywheel.java @@ -19,7 +19,7 @@ import com.jozufozu.flywheel.impl.BackendManagerImpl; import com.jozufozu.flywheel.impl.registry.IdRegistryImpl; import com.jozufozu.flywheel.impl.registry.RegistryImpl; import com.jozufozu.flywheel.impl.visualization.VisualizationEventHandler; -import com.jozufozu.flywheel.lib.context.Contexts; +import com.jozufozu.flywheel.lib.context.ContextShaders; import com.jozufozu.flywheel.lib.instance.InstanceTypes; import com.jozufozu.flywheel.lib.material.CutoutShaders; import com.jozufozu.flywheel.lib.material.FogShaders; @@ -128,7 +128,7 @@ public class Flywheel { CutoutShaders.init(); FogShaders.init(); StandardMaterialShaders.init(); - Contexts.init(); + ContextShaders.init(); ShaderIndices.init(); diff --git a/src/main/java/com/jozufozu/flywheel/api/backend/Engine.java b/src/main/java/com/jozufozu/flywheel/api/backend/Engine.java index e21e2658e..c43c21688 100644 --- a/src/main/java/com/jozufozu/flywheel/api/backend/Engine.java +++ b/src/main/java/com/jozufozu/flywheel/api/backend/Engine.java @@ -3,6 +3,7 @@ package com.jozufozu.flywheel.api.backend; import java.util.List; import com.jozufozu.flywheel.api.BackendImplemented; +import com.jozufozu.flywheel.api.context.Context; import com.jozufozu.flywheel.api.event.RenderContext; import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.instance.Instance; @@ -31,7 +32,7 @@ public interface Engine { * @return An instancer for the given instance type, model, and render stage. * @see InstancerProvider */ - Instancer instancer(InstanceType type, Model model, RenderStage stage); + Instancer instancer(InstanceType type, Context context, Model model, RenderStage stage); /** * Create a plan that will be executed every frame. diff --git a/src/main/java/com/jozufozu/flywheel/api/context/Context.java b/src/main/java/com/jozufozu/flywheel/api/context/Context.java index 769fb0c80..3126030d7 100644 --- a/src/main/java/com/jozufozu/flywheel/api/context/Context.java +++ b/src/main/java/com/jozufozu/flywheel/api/context/Context.java @@ -1,17 +1,16 @@ package com.jozufozu.flywheel.api.context; -import com.jozufozu.flywheel.api.internal.InternalFlywheelApi; -import com.jozufozu.flywheel.api.registry.Registry; -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; - -import net.minecraft.resources.ResourceLocation; +import com.jozufozu.flywheel.api.material.Material; public interface Context { - static Registry REGISTRY = InternalFlywheelApi.INSTANCE.createRegistry(); + ContextShader contextShader(); - void onProgramLink(GlProgram program); - - ResourceLocation vertexShader(); - - ResourceLocation fragmentShader(); + /** + * Prepare the shader for rendering with the given material and textures. + * + * @param material The material about to be rendered. + * @param shader The shader to prepare. + * @param textures Source of the textures to use. + */ + void prepare(Material material, Shader shader, Textures textures); } diff --git a/src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java b/src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java new file mode 100644 index 000000000..8c8dfef15 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/context/ContextShader.java @@ -0,0 +1,14 @@ +package com.jozufozu.flywheel.api.context; + +import com.jozufozu.flywheel.api.internal.InternalFlywheelApi; +import com.jozufozu.flywheel.api.registry.Registry; + +import net.minecraft.resources.ResourceLocation; + +public interface ContextShader { + static Registry REGISTRY = InternalFlywheelApi.INSTANCE.createRegistry(); + + ResourceLocation vertexShader(); + + ResourceLocation fragmentShader(); +} diff --git a/src/main/java/com/jozufozu/flywheel/api/context/Shader.java b/src/main/java/com/jozufozu/flywheel/api/context/Shader.java new file mode 100644 index 000000000..b7dbe1069 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/context/Shader.java @@ -0,0 +1,8 @@ +package com.jozufozu.flywheel.api.context; + +import com.jozufozu.flywheel.api.BackendImplemented; + +@BackendImplemented +public interface Shader { + void setTexture(String glslName, Texture texture); +} diff --git a/src/main/java/com/jozufozu/flywheel/api/context/Texture.java b/src/main/java/com/jozufozu/flywheel/api/context/Texture.java new file mode 100644 index 000000000..362abf38e --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/context/Texture.java @@ -0,0 +1,8 @@ +package com.jozufozu.flywheel.api.context; + +import com.jozufozu.flywheel.api.BackendImplemented; + +@BackendImplemented +public interface Texture { + void filter(boolean blur, boolean mipmap); +} diff --git a/src/main/java/com/jozufozu/flywheel/api/context/Textures.java b/src/main/java/com/jozufozu/flywheel/api/context/Textures.java new file mode 100644 index 000000000..65e859d33 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/context/Textures.java @@ -0,0 +1,32 @@ +package com.jozufozu.flywheel.api.context; + +import com.jozufozu.flywheel.api.BackendImplemented; + +import net.minecraft.resources.ResourceLocation; + +@BackendImplemented +public interface Textures { + /** + * Get a built-in texture by its resource location. + * + * @param texture The texture's resource location. + * @return The texture. + */ + Texture byName(ResourceLocation texture); + + /** + * Get the overlay texture. + * + * @return The overlay texture. + */ + Texture overlay(); + + /** + * Get the light texture. + * + * @return The light texture. + */ + Texture light(); + + // TODO: Allow creating dynamic textures. +} 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 ca25d9a84..8175ffd14 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/FlwPrograms.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/FlwPrograms.java @@ -7,7 +7,7 @@ import org.slf4j.LoggerFactory; import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.api.context.Context; +import com.jozufozu.flywheel.api.context.ContextShader; import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.backend.ShaderIndices; import com.jozufozu.flywheel.backend.compile.component.UberShaderComponent; @@ -46,9 +46,9 @@ public final class FlwPrograms { private static ImmutableList createPipelineKeys() { ImmutableList.Builder builder = ImmutableList.builder(); - for (Context context : Context.REGISTRY) { + for (ContextShader contextShader : ContextShader.REGISTRY) { for (InstanceType instanceType : InstanceType.REGISTRY) { - builder.add(new PipelineProgramKey(instanceType, context)); + builder.add(new PipelineProgramKey(instanceType, contextShader)); } } return builder.build(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/IndirectPrograms.java b/src/main/java/com/jozufozu/flywheel/backend/compile/IndirectPrograms.java index f53557db2..d0cc23574 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/IndirectPrograms.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/IndirectPrograms.java @@ -7,7 +7,7 @@ import org.jetbrains.annotations.Nullable; import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.api.context.Context; +import com.jozufozu.flywheel.api.context.ContextShader; import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.backend.compile.component.IndirectComponent; import com.jozufozu.flywheel.backend.compile.core.CompilationHarness; @@ -121,7 +121,7 @@ public class IndirectPrograms extends AbstractPrograms { return instance != null; } - public GlProgram getIndirectProgram(InstanceType instanceType, Context contextShader) { + public GlProgram getIndirectProgram(InstanceType instanceType, ContextShader contextShader) { return pipeline.get(new PipelineProgramKey(instanceType, contextShader)); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/InstancingPrograms.java b/src/main/java/com/jozufozu/flywheel/backend/compile/InstancingPrograms.java index 06cae2029..4af2eee68 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/InstancingPrograms.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/InstancingPrograms.java @@ -6,7 +6,7 @@ import java.util.Map; import org.jetbrains.annotations.Nullable; import com.google.common.collect.ImmutableList; -import com.jozufozu.flywheel.api.context.Context; +import com.jozufozu.flywheel.api.context.ContextShader; import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.backend.glsl.ShaderSources; @@ -61,7 +61,7 @@ public class InstancingPrograms extends AbstractPrograms { return instance != null; } - public GlProgram get(InstanceType instanceType, Context contextShader) { + public GlProgram get(InstanceType instanceType, ContextShader contextShader) { return pipeline.get(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 2d3a7f71f..cdc5c3e31 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/PipelineCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/PipelineCompiler.java @@ -50,8 +50,6 @@ public class PipelineCompiler { .fragmentShader()) .withResource(pipeline.fragmentMain())) .then((key, program) -> { - key.contextShader() - .onProgramLink(program); program.setUniformBlockBinding("_FlwFrameUniforms", 0); program.setUniformBlockBinding("_FlwFogUniforms", 1); }) diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/PipelineProgramKey.java b/src/main/java/com/jozufozu/flywheel/backend/compile/PipelineProgramKey.java index 57050a0b3..2f39c68da 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/PipelineProgramKey.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/PipelineProgramKey.java @@ -1,6 +1,6 @@ package com.jozufozu.flywheel.backend.compile; -import com.jozufozu.flywheel.api.context.Context; +import com.jozufozu.flywheel.api.context.ContextShader; import com.jozufozu.flywheel.api.instance.InstanceType; /** @@ -9,5 +9,5 @@ import com.jozufozu.flywheel.api.instance.InstanceType; * @param instanceType The instance shader to use. * @param contextShader The context shader to use. */ -public record PipelineProgramKey(InstanceType instanceType, Context contextShader) { +public record PipelineProgramKey(InstanceType instanceType, ContextShader contextShader) { } 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 d96cefad4..2a9d9f3d0 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractEngine.java @@ -1,6 +1,7 @@ package com.jozufozu.flywheel.backend.engine; import com.jozufozu.flywheel.api.backend.Engine; +import com.jozufozu.flywheel.api.context.Context; import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.instance.Instance; import com.jozufozu.flywheel.api.instance.InstanceType; @@ -21,8 +22,8 @@ public abstract class AbstractEngine implements Engine { } @Override - public Instancer instancer(InstanceType type, Model model, RenderStage stage) { - return getStorage().getInstancer(type, model, stage); + public Instancer instancer(InstanceType type, Context context, Model model, RenderStage stage) { + return getStorage().getInstancer(type, context, model, stage); } @Override 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 6cfe224a8..37efbcf32 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/AbstractInstancer.java @@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.engine; import java.util.ArrayList; +import com.jozufozu.flywheel.api.context.Context; import com.jozufozu.flywheel.api.instance.Instance; import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.api.instance.Instancer; @@ -9,6 +10,7 @@ import com.jozufozu.flywheel.lib.util.AtomicBitset; public abstract class AbstractInstancer implements Instancer { public final InstanceType type; + public final Context context; // Lock for all instances, only needs to be used in methods that may run on the TaskExecutor. protected final Object lock = new Object(); @@ -18,8 +20,9 @@ public abstract class AbstractInstancer implements Instancer protected final AtomicBitset changed = new AtomicBitset(); protected final AtomicBitset deleted = new AtomicBitset(); - protected AbstractInstancer(InstanceType type) { + protected AbstractInstancer(InstanceType type, Context context) { this.type = type; + this.context = context; } @Override 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 d868ffb54..148c9963e 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerKey.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerKey.java @@ -1,9 +1,10 @@ package com.jozufozu.flywheel.backend.engine; +import com.jozufozu.flywheel.api.context.Context; 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; -public record InstancerKey(InstanceType type, Model model, RenderStage stage) { +public record InstancerKey(InstanceType type, Context context, Model model, RenderStage stage) { } 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 20f06db10..66050c00b 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerStorage.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/InstancerStorage.java @@ -6,6 +6,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import com.jozufozu.flywheel.Flywheel; +import com.jozufozu.flywheel.api.context.Context; import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.instance.Instance; import com.jozufozu.flywheel.api.instance.InstanceType; @@ -27,8 +28,8 @@ public abstract class InstancerStorage> { protected final List> initializationQueue = new ArrayList<>(); @SuppressWarnings("unchecked") - public Instancer getInstancer(InstanceType type, Model model, RenderStage stage) { - return (Instancer) instancers.computeIfAbsent(new InstancerKey<>(type, model, stage), this::createAndDeferInit); + public Instancer getInstancer(InstanceType type, Context context, Model model, RenderStage stage) { + return (Instancer) instancers.computeIfAbsent(new InstancerKey<>(type, context, model, stage), this::createAndDeferInit); } public void delete() { @@ -50,12 +51,12 @@ public abstract class InstancerStorage> { .forEach(AbstractInstancer::clear); } - protected abstract N create(InstanceType type); + protected abstract N create(InstancerKey type); protected abstract void initialize(InstancerKey key, N instancer); private N createAndDeferInit(InstancerKey key) { - var out = create(key.type()); + var out = create(key); // Only queue the instancer for initialization if it has anything to render. if (key.model() diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/MaterialRenderState.java b/src/main/java/com/jozufozu/flywheel/backend/engine/MaterialRenderState.java index 0eb1636a6..234e70e06 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/MaterialRenderState.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/MaterialRenderState.java @@ -8,13 +8,9 @@ import com.jozufozu.flywheel.api.material.DepthTest; import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.material.Transparency; import com.jozufozu.flywheel.api.material.WriteMask; -import com.jozufozu.flywheel.backend.gl.GlTextureUnit; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.texture.AbstractTexture; - public final class MaterialRenderState { public static final Comparator COMPARATOR = Comparator.comparing(Material::texture) .thenComparing(Material::blur) @@ -29,7 +25,6 @@ public final class MaterialRenderState { } public static void setup(Material material) { - setupTexture(material); setupBackfaceCulling(material.backfaceCulling()); setupPolygonOffset(material.polygonOffset()); setupDepthTest(material.depthTest()); @@ -37,17 +32,6 @@ public final class MaterialRenderState { setupWriteMask(material.writeMask()); } - private static void setupTexture(Material material) { - GlTextureUnit.T0.makeActive(); - AbstractTexture texture = Minecraft.getInstance() - .getTextureManager() - .getTexture(material.texture()); - texture.setFilter(material.blur(), material.mipmap()); - var textureId = texture.getId(); - RenderSystem.setShaderTexture(0, textureId); - RenderSystem.bindTexture(textureId); - } - private static void setupBackfaceCulling(boolean backfaceCulling) { if (backfaceCulling) { RenderSystem.enableCull(); @@ -141,7 +125,6 @@ public final class MaterialRenderState { } public static void reset() { - resetTexture(); resetBackfaceCulling(); resetPolygonOffset(); resetDepthTest(); @@ -149,11 +132,6 @@ public final class MaterialRenderState { resetWriteMask(); } - private static void resetTexture() { - GlTextureUnit.T0.makeActive(); - RenderSystem.setShaderTexture(0, 0); - } - private static void resetBackfaceCulling() { RenderSystem.enableCull(); } 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 286ee0ee0..c12fba537 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 @@ -16,6 +16,7 @@ import java.util.EnumMap; import java.util.List; import java.util.Map; +import com.jozufozu.flywheel.api.context.Context; import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.instance.Instance; import com.jozufozu.flywheel.api.instance.InstanceType; @@ -24,11 +25,13 @@ import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.model.Model; import com.jozufozu.flywheel.backend.compile.IndirectPrograms; import com.jozufozu.flywheel.backend.engine.MaterialRenderState; +import com.jozufozu.flywheel.backend.engine.textures.TextureBinder; +import com.jozufozu.flywheel.backend.engine.textures.TexturesImpl; import com.jozufozu.flywheel.backend.engine.uniform.Uniforms; import com.jozufozu.flywheel.backend.gl.Driver; import com.jozufozu.flywheel.backend.gl.GlCompat; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; -import com.jozufozu.flywheel.lib.context.Contexts; +import com.jozufozu.flywheel.lib.context.SimpleContextShader; public class IndirectCullingGroup { private static final Comparator DRAW_COMPARATOR = Comparator.comparing(IndirectDraw::stage) @@ -37,6 +40,7 @@ public class IndirectCullingGroup { private static final int DRAW_BARRIER_BITS = GL_SHADER_STORAGE_BARRIER_BIT | GL_COMMAND_BARRIER_BIT; private final InstanceType instanceType; + private final Context context; private final long objectStride; private final IndirectBuffers buffers; private final IndirectMeshPool meshPool; @@ -53,17 +57,19 @@ public class IndirectCullingGroup { private boolean hasNewDraws; private int instanceCountThisFrame; - IndirectCullingGroup(InstanceType instanceType, IndirectPrograms programs) { + IndirectCullingGroup(InstanceType instanceType, Context context, IndirectPrograms programs) { this.instanceType = instanceType; + this.context = context; objectStride = instanceType.layout() .byteSize() + IndirectBuffers.INT_SIZE; buffers = new IndirectBuffers(objectStride); meshPool = new IndirectMeshPool(); this.programs = programs; + // TODO: Culling programs need to be context aware. cullProgram = programs.getCullingProgram(instanceType); applyProgram = programs.getApplyProgram(); - drawProgram = programs.getIndirectProgram(instanceType, Contexts.DEFAULT); + drawProgram = programs.getIndirectProgram(instanceType, context.contextShader()); } public void flush(StagingBuffer stagingBuffer) { @@ -179,7 +185,7 @@ public class IndirectCullingGroup { hasNewDraws = true; } - public void submit(RenderStage stage) { + public void submit(RenderStage stage, TexturesImpl textures) { if (nothingToDo(stage)) { return; } @@ -195,12 +201,17 @@ public class IndirectCullingGroup { for (var multiDraw : multiDraws.get(stage)) { glUniform1ui(flwBaseDraw, multiDraw.start); + + context.prepare(multiDraw.material, drawProgram, textures); + MaterialRenderState.setup(multiDraw.material); + multiDraw.submit(); + TextureBinder.resetTextureBindings(); } } - public void bindForCrumbling() { - var program = programs.getIndirectProgram(instanceType, Contexts.CRUMBLING); + public void bindWithContextShader(SimpleContextShader override) { + var program = programs.getIndirectProgram(instanceType, override); program.bind(); @@ -265,16 +276,14 @@ public class IndirectCullingGroup { } private record MultiDraw(Material material, int start, int end) { - void submit() { - MaterialRenderState.setup(material); - + private void submit() { if (GlCompat.DRIVER == Driver.INTEL) { // Intel renders garbage with MDI, but Consecutive Normal Draws works fine. - for (int i = start; i < end; i++) { + for (int i = this.start; i < this.end; i++) { glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, i * IndirectBuffers.DRAW_COMMAND_STRIDE); } } else { - glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, start * IndirectBuffers.DRAW_COMMAND_STRIDE, end - start, (int) IndirectBuffers.DRAW_COMMAND_STRIDE); + glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, this.start * IndirectBuffers.DRAW_COMMAND_STRIDE, this.end - this.start, (int) IndirectBuffers.DRAW_COMMAND_STRIDE); } } } 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 b3985fdfa..98e664df2 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 @@ -12,6 +12,7 @@ import java.util.List; import java.util.Map; import com.jozufozu.flywheel.api.backend.Engine; +import com.jozufozu.flywheel.api.context.Context; import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.instance.Instance; import com.jozufozu.flywheel.api.instance.InstanceType; @@ -21,8 +22,10 @@ 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.textures.TexturesImpl; import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer; import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType; +import com.jozufozu.flywheel.lib.context.ContextShaders; import com.jozufozu.flywheel.lib.material.SimpleMaterial; import com.jozufozu.flywheel.lib.memory.MemoryBlock; import com.jozufozu.flywheel.lib.util.Pair; @@ -34,7 +37,8 @@ import net.minecraft.client.resources.model.ModelBakery; public class IndirectDrawManager extends InstancerStorage> { private final IndirectPrograms programs; private final StagingBuffer stagingBuffer; - private final Map, IndirectCullingGroup> cullingGroups = new HashMap<>(); + private final TexturesImpl textures = new TexturesImpl(); + private final Map, IndirectCullingGroup> cullingGroups = new HashMap<>(); private final GlBuffer crumblingDrawBuffer = new GlBuffer(); public IndirectDrawManager(IndirectPrograms programs) { @@ -43,14 +47,15 @@ public class IndirectDrawManager extends InstancerStorage> } @Override - protected IndirectInstancer create(InstanceType type) { - return new IndirectInstancer<>(type); + protected IndirectInstancer create(InstancerKey key) { + return new IndirectInstancer<>(key.type(), key.context()); } @SuppressWarnings("unchecked") @Override protected void initialize(InstancerKey key, IndirectInstancer instancer) { - var group = (IndirectCullingGroup) cullingGroups.computeIfAbsent(key.type(), t -> new IndirectCullingGroup<>(t, programs)); + var groupKey = new GroupKey<>(key.type(), key.context()); + var group = (IndirectCullingGroup) cullingGroups.computeIfAbsent(groupKey, t -> new IndirectCullingGroup<>(t.type, t.context, programs)); group.add((IndirectInstancer) instancer, key.model(), key.stage()); } @@ -65,7 +70,7 @@ public class IndirectDrawManager extends InstancerStorage> public void renderStage(RenderStage stage) { for (var group : cullingGroups.values()) { - group.submit(stage); + group.submit(stage, textures); } } @@ -123,7 +128,7 @@ public class IndirectDrawManager extends InstancerStorage> // Set up the crumbling program buffers. Nothing changes here between draws. cullingGroups.get(instanceTypeEntry.getKey()) - .bindForCrumbling(); + .bindWithContextShader(ContextShaders.CRUMBLING); for (var progressEntry : byProgress.int2ObjectEntrySet()) { for (var instanceHandlePair : progressEntry.getValue()) { @@ -156,8 +161,8 @@ public class IndirectDrawManager extends InstancerStorage> block.free(); } - private static Map, Int2ObjectMap, InstanceHandleImpl>>>> doCrumblingSort(List crumblingBlocks) { - Map, Int2ObjectMap, InstanceHandleImpl>>>> byType = new HashMap<>(); + private static Map, Int2ObjectMap, InstanceHandleImpl>>>> doCrumblingSort(List crumblingBlocks) { + Map, Int2ObjectMap, InstanceHandleImpl>>>> byType = new HashMap<>(); for (Engine.CrumblingBlock block : crumblingBlocks) { int progress = block.progress(); @@ -176,11 +181,14 @@ public class IndirectDrawManager extends InstancerStorage> continue; } - byType.computeIfAbsent(instancer.type, $ -> new Int2ObjectArrayMap<>()) + byType.computeIfAbsent(new GroupKey<>(instancer.type, instancer.context), $ -> new Int2ObjectArrayMap<>()) .computeIfAbsent(progress, $ -> new ArrayList<>()) .add(Pair.of(instancer, impl)); } } return byType; } + + public record GroupKey(InstanceType type, Context context) { + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java index 6b0a8bb58..f022ad107 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java @@ -13,15 +13,9 @@ import com.jozufozu.flywheel.backend.engine.InstancerStorage; import com.jozufozu.flywheel.backend.engine.MaterialRenderState; import com.jozufozu.flywheel.backend.engine.uniform.Uniforms; import com.jozufozu.flywheel.backend.gl.GlStateTracker; -import com.jozufozu.flywheel.backend.gl.GlTextureUnit; import com.jozufozu.flywheel.lib.task.Flag; import com.jozufozu.flywheel.lib.task.NamedFlag; import com.jozufozu.flywheel.lib.task.SyncedPlan; -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.systems.RenderSystem; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.GameRenderer; public class IndirectEngine extends AbstractEngine { private final IndirectPrograms programs; @@ -60,23 +54,9 @@ public class IndirectEngine extends AbstractEngine { } try (var restoreState = GlStateTracker.getRestoreState()) { - GameRenderer gameRenderer = Minecraft.getInstance().gameRenderer; - int prevActiveTexture = GlStateManager._getActiveTexture(); - gameRenderer.overlayTexture().setupOverlayColor(); - gameRenderer.lightTexture().turnOnLightLayer(); - - GlTextureUnit.T1.makeActive(); - RenderSystem.bindTexture(RenderSystem.getShaderTexture(1)); - GlTextureUnit.T2.makeActive(); - RenderSystem.bindTexture(RenderSystem.getShaderTexture(2)); - drawManager.renderStage(stage); MaterialRenderState.reset(); - - gameRenderer.overlayTexture().teardownOverlayColor(); - gameRenderer.lightTexture().turnOffLightLayer(); - GlStateManager._activeTexture(prevActiveTexture); } } 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 1e305ed97..411d7e58f 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 @@ -5,6 +5,7 @@ import java.util.List; import org.lwjgl.system.MemoryUtil; +import com.jozufozu.flywheel.api.context.Context; import com.jozufozu.flywheel.api.instance.Instance; import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.api.instance.InstanceWriter; @@ -18,8 +19,8 @@ public class IndirectInstancer extends AbstractInstancer private long lastStartPos = -1; - public IndirectInstancer(InstanceType type) { - super(type); + public IndirectInstancer(InstanceType type, Context context) { + super(type, context); this.objectStride = type.layout() .byteSize() + IndirectBuffers.INT_SIZE; writer = this.type.writer(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/DrawCall.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/DrawCall.java index af0f59552..86aa9c8bf 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/DrawCall.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/DrawCall.java @@ -1,5 +1,7 @@ package com.jozufozu.flywheel.backend.engine.instancing; +import org.jetbrains.annotations.Nullable; + import com.jozufozu.flywheel.backend.InternalVertex; import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl; import com.jozufozu.flywheel.backend.gl.array.GlVertexArray; @@ -9,7 +11,9 @@ public class DrawCall { private final InstancedInstancer instancer; private final InstancedMeshPool.BufferedMesh mesh; + @Nullable private GlVertexArray vao; + @Nullable private GlVertexArray vaoScratch; public DrawCall(InstancedInstancer instancer, InstancedMeshPool.BufferedMesh mesh, ShaderState shaderState) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedCrumbling.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedCrumbling.java index e8623af5c..5fa323478 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedCrumbling.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedCrumbling.java @@ -13,7 +13,7 @@ import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl; import com.jozufozu.flywheel.backend.engine.MaterialRenderState; import com.jozufozu.flywheel.backend.engine.uniform.Uniforms; import com.jozufozu.flywheel.backend.gl.GlStateTracker; -import com.jozufozu.flywheel.lib.context.Contexts; +import com.jozufozu.flywheel.lib.context.ContextShaders; import com.jozufozu.flywheel.lib.material.SimpleMaterial; import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; @@ -46,7 +46,7 @@ public class InstancedCrumbling { CommonCrumbling.applyCrumblingProperties(crumblingMaterial, baseMaterial); - var program = programs.get(shader.instanceType(), Contexts.CRUMBLING); + var program = programs.get(shader.instanceType(), ContextShaders.CRUMBLING); program.bind(); Uniforms.bindForDraw(); 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 1afcb82fa..24abbf9de 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 @@ -10,7 +10,6 @@ import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ListMultimap; 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.Mesh; import com.jozufozu.flywheel.backend.engine.InstancerKey; import com.jozufozu.flywheel.backend.engine.InstancerStorage; @@ -56,8 +55,8 @@ public class InstancedDrawManager extends InstancerStorage } @Override - protected InstancedInstancer create(InstanceType type) { - return new InstancedInstancer<>(type); + protected InstancedInstancer create(InstancerKey key) { + return new InstancedInstancer<>(key.type(), key.context()); } @Override @@ -71,7 +70,7 @@ public class InstancedDrawManager extends InstancerStorage for (var entry : meshes.entrySet()) { var mesh = alloc(entry.getValue()); - ShaderState shaderState = new ShaderState(entry.getKey(), instancer.type); + ShaderState shaderState = new ShaderState(entry.getKey(), key.type(), key.context()); DrawCall drawCall = new DrawCall(instancer, mesh, shaderState); drawSet.put(shaderState, drawCall); 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 ab9498400..8dabe219f 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 @@ -5,7 +5,10 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import org.jetbrains.annotations.Nullable; + import com.jozufozu.flywheel.Flywheel; +import com.jozufozu.flywheel.api.context.Context; import com.jozufozu.flywheel.api.instance.Instance; import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.api.instance.InstanceWriter; @@ -23,12 +26,13 @@ public class InstancedInstancer extends AbstractInstancer private final Set boundTo = new HashSet<>(); private final InstanceWriter writer; + @Nullable private GlBuffer vbo; private final List drawCalls = new ArrayList<>(); - public InstancedInstancer(InstanceType type) { - super(type); + public InstancedInstancer(InstanceType type, Context context) { + super(type, context); var layout = type.layout(); instanceAttributes = LayoutAttributes.attributes(layout); instanceStride = layout.byteSize(); @@ -68,7 +72,7 @@ public class InstancedInstancer extends AbstractInstancer } private void updateBuffer() { - if (changed.isEmpty()) { + if (changed.isEmpty() || vbo == null) { return; } @@ -120,6 +124,9 @@ public class InstancedInstancer extends AbstractInstancer } public void delete() { + if (vbo == null) { + return; + } vbo.delete(); vbo = null; } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java index a83be2852..b09a31b0c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java @@ -16,22 +16,18 @@ import com.jozufozu.flywheel.backend.engine.AbstractInstancer; import com.jozufozu.flywheel.backend.engine.InstancerStorage; import com.jozufozu.flywheel.backend.engine.MaterialEncoder; import com.jozufozu.flywheel.backend.engine.MaterialRenderState; +import com.jozufozu.flywheel.backend.engine.textures.TextureBinder; +import com.jozufozu.flywheel.backend.engine.textures.TexturesImpl; import com.jozufozu.flywheel.backend.engine.uniform.Uniforms; import com.jozufozu.flywheel.backend.gl.GlStateTracker; -import com.jozufozu.flywheel.backend.gl.GlTextureUnit; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; -import com.jozufozu.flywheel.lib.context.Contexts; import com.jozufozu.flywheel.lib.task.Flag; import com.jozufozu.flywheel.lib.task.NamedFlag; import com.jozufozu.flywheel.lib.task.SyncedPlan; -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.systems.RenderSystem; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.GameRenderer; public class InstancingEngine extends AbstractEngine { private final InstancingPrograms programs; + private final TexturesImpl textures = new TexturesImpl(); private final InstancedDrawManager drawManager = new InstancedDrawManager(); private final Flag flushFlag = new NamedFlag("flushed"); @@ -68,21 +64,7 @@ public class InstancingEngine extends AbstractEngine { } try (var state = GlStateTracker.getRestoreState()) { - GameRenderer gameRenderer = Minecraft.getInstance().gameRenderer; - int prevActiveTexture = GlStateManager._getActiveTexture(); - gameRenderer.overlayTexture().setupOverlayColor(); - gameRenderer.lightTexture().turnOnLightLayer(); - - GlTextureUnit.T1.makeActive(); - RenderSystem.bindTexture(RenderSystem.getShaderTexture(1)); - GlTextureUnit.T2.makeActive(); - RenderSystem.bindTexture(RenderSystem.getShaderTexture(2)); - render(drawSet); - - gameRenderer.overlayTexture().teardownOverlayColor(); - gameRenderer.lightTexture().turnOffLightLayer(); - GlStateManager._activeTexture(prevActiveTexture); } } @@ -116,17 +98,21 @@ public class InstancingEngine extends AbstractEngine { continue; } - var program = programs.get(shader.instanceType(), Contexts.DEFAULT); + var program = programs.get(shader.instanceType(), shader.context() + .contextShader()); program.bind(); Uniforms.bindForDraw(); uploadMaterialUniform(program, shader.material()); + shader.context() + .prepare(shader.material(), program, textures); MaterialRenderState.setup(shader.material()); for (var drawCall : drawCalls) { drawCall.render(); } + TextureBinder.resetTextureBindings(); } MaterialRenderState.reset(); 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 28b4955eb..e92992998 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 @@ -1,7 +1,8 @@ package com.jozufozu.flywheel.backend.engine.instancing; +import com.jozufozu.flywheel.api.context.Context; import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.api.material.Material; -public record ShaderState(Material material, InstanceType instanceType) { +public record ShaderState(Material material, InstanceType instanceType, Context context) { } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/textures/IdentifiedTexture.java b/src/main/java/com/jozufozu/flywheel/backend/engine/textures/IdentifiedTexture.java new file mode 100644 index 000000000..4f441c8da --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/textures/IdentifiedTexture.java @@ -0,0 +1,13 @@ +package com.jozufozu.flywheel.backend.engine.textures; + +import com.jozufozu.flywheel.api.context.Texture; + +/** + * Internal base interface that {@link com.jozufozu.flywheel.backend.gl.shader.GlProgram GlProgram} expects. + */ +public interface IdentifiedTexture extends Texture { + /** + * @return The GL texture id of this texture. + */ + int id(); +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/textures/TextureBinder.java b/src/main/java/com/jozufozu/flywheel/backend/engine/textures/TextureBinder.java new file mode 100644 index 000000000..982ee3341 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/textures/TextureBinder.java @@ -0,0 +1,41 @@ +package com.jozufozu.flywheel.backend.engine.textures; + +import static org.lwjgl.opengl.GL13.GL_TEXTURE0; + +import com.mojang.blaze3d.systems.RenderSystem; + +import it.unimi.dsi.fastutil.ints.Int2IntArrayMap; +import it.unimi.dsi.fastutil.ints.Int2IntMap; + +public class TextureBinder { + // TODO: some kind of cache eviction when the program changes + // so we don't always reset and bind the light and overlay textures? + private static final Int2IntMap texturesToSamplerUnits = new Int2IntArrayMap(); + private static int nextSamplerUnit = 0; + + /** + * Binds the given texture to the next available texture unit, returning the unit it was bound to. + * + * @param id The id of the texture to bind. + * @return The texture unit the texture was bound to. + */ + public static int bindTexture(int id) { + return texturesToSamplerUnits.computeIfAbsent(id, i -> { + int unit = nextSamplerUnit++; + RenderSystem.activeTexture(GL_TEXTURE0 + unit); + RenderSystem.bindTexture(i); + return unit; + }); + } + + public static void resetTextureBindings() { + nextSamplerUnit = 0; + + for (Int2IntMap.Entry entry : texturesToSamplerUnits.int2IntEntrySet()) { + RenderSystem.activeTexture(GL_TEXTURE0 + entry.getIntValue()); + RenderSystem.bindTexture(0); + } + + texturesToSamplerUnits.clear(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/textures/TexturesImpl.java b/src/main/java/com/jozufozu/flywheel/backend/engine/textures/TexturesImpl.java new file mode 100644 index 000000000..0c4e52465 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/textures/TexturesImpl.java @@ -0,0 +1,66 @@ +package com.jozufozu.flywheel.backend.engine.textures; + +import java.util.HashMap; +import java.util.Map; + +import com.jozufozu.flywheel.api.context.Texture; +import com.jozufozu.flywheel.api.context.Textures; +import com.jozufozu.flywheel.backend.mixin.LightTextureAccessor; +import com.jozufozu.flywheel.backend.mixin.OverlayTextureAccessor; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.AbstractTexture; +import net.minecraft.resources.ResourceLocation; + +public class TexturesImpl implements Textures { + + private final DirectTexture lightTexture; + private final DirectTexture overlayTexture; + private final Map wrappers = new HashMap<>(); + + public TexturesImpl() { + var gameRenderer = Minecraft.getInstance().gameRenderer; + + this.lightTexture = new DirectTexture(((LightTextureAccessor) gameRenderer.lightTexture()).flywheel$texture() + .getId()); + this.overlayTexture = new DirectTexture(((OverlayTextureAccessor) gameRenderer.overlayTexture()).flywheel$texture() + .getId()); + } + + + @Override + public Texture byName(ResourceLocation texture) { + return wrappers.computeIfAbsent(texture, key -> new WrappedTexture(Minecraft.getInstance() + .getTextureManager() + .getTexture(key))); + } + + @Override + public Texture overlay() { + return overlayTexture; + } + + @Override + public Texture light() { + return lightTexture; + } + + public record WrappedTexture(AbstractTexture texture) implements IdentifiedTexture { + @Override + public void filter(boolean blur, boolean mipmap) { + texture.setFilter(blur, mipmap); + } + + @Override + public int id() { + return texture.getId(); + } + } + + public record DirectTexture(int id) implements IdentifiedTexture { + @Override + public void filter(boolean blur, boolean mipmap) { + // no-op + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/GlStateTracker.java b/src/main/java/com/jozufozu/flywheel/backend/gl/GlStateTracker.java index 0e3012c2e..ebdb56b20 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/GlStateTracker.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/GlStateTracker.java @@ -36,7 +36,7 @@ public class GlStateTracker { } public static State getRestoreState() { - return new State(BUFFERS.clone(), vao, program); + return new State(BUFFERS.clone(), vao, program, GlStateManager._getActiveTexture()); } public static void bindVao(int vao) { @@ -51,7 +51,7 @@ public class GlStateTracker { } } - public record State(int[] buffers, int vao, int program) implements AutoCloseable { + public record State(int[] buffers, int vao, int program, int activeTexture) implements AutoCloseable { public void restore() { if (vao != GlStateTracker.vao) { GlStateManager._glBindVertexArray(vao); @@ -68,6 +68,8 @@ public class GlStateTracker { if (program != GlStateTracker.program) { GlStateManager._glUseProgram(program); } + + GlStateManager._activeTexture(activeTexture); } @Override diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlProgram.java b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlProgram.java index 308e39645..5c1665fd0 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlProgram.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/shader/GlProgram.java @@ -9,6 +9,10 @@ import static org.lwjgl.opengl.GL31.glUniformBlockBinding; import org.slf4j.Logger; +import com.jozufozu.flywheel.api.context.Shader; +import com.jozufozu.flywheel.api.context.Texture; +import com.jozufozu.flywheel.backend.engine.textures.IdentifiedTexture; +import com.jozufozu.flywheel.backend.engine.textures.TextureBinder; import com.jozufozu.flywheel.backend.gl.GlObject; import com.mojang.blaze3d.shaders.ProgramManager; import com.mojang.logging.LogUtils; @@ -16,7 +20,7 @@ import com.mojang.logging.LogUtils; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -public class GlProgram extends GlObject { +public class GlProgram extends GlObject implements Shader { private static final Logger LOGGER = LogUtils.getLogger(); private final Object2IntMap uniformLocationCache = new Object2IntOpenHashMap<>(); @@ -33,6 +37,24 @@ public class GlProgram extends GlObject { ProgramManager.glUseProgram(0); } + @Override + public void setTexture(String glslName, Texture texture) { + if (!(texture instanceof IdentifiedTexture identified)) { + return; + } + int uniform = getUniformLocation(glslName); + + if (uniform < 0) { + return; + } + + int id = identified.id(); + + int binding = TextureBinder.bindTexture(id); + + glUniform1i(uniform, binding); + } + /** * Retrieves the index of the uniform with the given name. * diff --git a/src/main/java/com/jozufozu/flywheel/backend/mixin/LightTextureAccessor.java b/src/main/java/com/jozufozu/flywheel/backend/mixin/LightTextureAccessor.java new file mode 100644 index 000000000..edda4df14 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/mixin/LightTextureAccessor.java @@ -0,0 +1,13 @@ +package com.jozufozu.flywheel.backend.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.texture.DynamicTexture; + +@Mixin(LightTexture.class) +public interface LightTextureAccessor { + @Accessor("lightTexture") + DynamicTexture flywheel$texture(); +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/mixin/OverlayTextureAccessor.java b/src/main/java/com/jozufozu/flywheel/backend/mixin/OverlayTextureAccessor.java new file mode 100644 index 000000000..0f5af0ca6 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/mixin/OverlayTextureAccessor.java @@ -0,0 +1,13 @@ +package com.jozufozu.flywheel.backend.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.client.renderer.texture.OverlayTexture; + +@Mixin(OverlayTexture.class) +public interface OverlayTextureAccessor { + @Accessor("texture") + DynamicTexture flywheel$texture(); +} diff --git a/src/main/java/com/jozufozu/flywheel/impl/visualization/InstancerProviderImpl.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/InstancerProviderImpl.java index aea75eb37..c354427a1 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/visualization/InstancerProviderImpl.java +++ b/src/main/java/com/jozufozu/flywheel/impl/visualization/InstancerProviderImpl.java @@ -10,12 +10,13 @@ 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.VisualizationContext; +import com.jozufozu.flywheel.lib.context.Contexts; public record InstancerProviderImpl(Engine engine, RenderStage renderStage) implements InstancerProvider, Supplier { @Override public Instancer instancer(InstanceType type, Model model) { - return engine.instancer(type, model, renderStage); + return engine.instancer(type, Contexts.DEFAULT, model, renderStage); } @Override diff --git a/src/main/java/com/jozufozu/flywheel/lib/context/ContextShaders.java b/src/main/java/com/jozufozu/flywheel/lib/context/ContextShaders.java new file mode 100644 index 000000000..cd3f69120 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/context/ContextShaders.java @@ -0,0 +1,18 @@ +package com.jozufozu.flywheel.lib.context; + +import org.jetbrains.annotations.ApiStatus; + +import com.jozufozu.flywheel.Flywheel; +import com.jozufozu.flywheel.api.context.ContextShader; + +public class ContextShaders { + public static final SimpleContextShader DEFAULT = ContextShader.REGISTRY.registerAndGet(new SimpleContextShader(Flywheel.rl("context/default.vert"), Flywheel.rl("context/default.frag"))); + public static final SimpleContextShader CRUMBLING = ContextShader.REGISTRY.registerAndGet(new SimpleContextShader(Flywheel.rl("context/crumbling.vert"), Flywheel.rl("context/crumbling.frag"))); + + private ContextShaders() { + } + + @ApiStatus.Internal + public static void init() { + } +} diff --git a/src/main/java/com/jozufozu/flywheel/lib/context/Contexts.java b/src/main/java/com/jozufozu/flywheel/lib/context/Contexts.java index f54ff4bb8..22f4007ab 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/context/Contexts.java +++ b/src/main/java/com/jozufozu/flywheel/lib/context/Contexts.java @@ -1,37 +1,48 @@ package com.jozufozu.flywheel.lib.context; -import org.jetbrains.annotations.ApiStatus; - -import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.context.Context; -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; +import com.jozufozu.flywheel.api.context.ContextShader; +import com.jozufozu.flywheel.api.context.Shader; +import com.jozufozu.flywheel.api.context.Textures; +import com.jozufozu.flywheel.api.material.Material; + +import net.minecraft.client.resources.model.ModelBakery; public final class Contexts { - public static final SimpleContext DEFAULT = Context.REGISTRY.registerAndGet(new SimpleContext( - Flywheel.rl("context/default.vert"), - Flywheel.rl("context/default.frag"), - program -> { - program.bind(); - program.setSamplerBinding("_flw_diffuseTex", 0); - program.setSamplerBinding("_flw_overlayTex", 1); - program.setSamplerBinding("_flw_lightTex", 2); - GlProgram.unbind(); - })); + public static final Context DEFAULT = new Context() { + @Override + public ContextShader contextShader() { + return ContextShaders.DEFAULT; + } - public static final SimpleContext CRUMBLING = Context.REGISTRY.registerAndGet(new SimpleContext( - Flywheel.rl("context/crumbling.vert"), - Flywheel.rl("context/crumbling.frag"), - program -> { - program.bind(); - program.setSamplerBinding("_flw_crumblingTex", 0); - program.setSamplerBinding("_flw_diffuseTex", 1); - GlProgram.unbind(); - })); + @Override + public void prepare(Material material, Shader shader, Textures textures) { + var texture = textures.byName(material.texture()); + texture.filter(material.blur(), material.mipmap()); + shader.setTexture("_flw_diffuseTex", texture); + + shader.setTexture("_flw_overlayTex", textures.overlay()); + shader.setTexture("_flw_lightTex", textures.light()); + } + }; + + public static final Context CRUMBLING = new Context() { + @Override + public ContextShader contextShader() { + return ContextShaders.CRUMBLING; + } + + @Override + public void prepare(Material material, Shader shader, Textures textures) { + var texture = textures.byName(material.texture()); + texture.filter(material.blur(), material.mipmap()); + shader.setTexture("_flw_diffuseTex", texture); + + var crumblingTexture = textures.byName(ModelBakery.BREAKING_LOCATIONS.get(0)); + shader.setTexture("_flw_crumblingTex", crumblingTexture); + } + }; private Contexts() { } - - @ApiStatus.Internal - public static void init() { - } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/context/SimpleContext.java b/src/main/java/com/jozufozu/flywheel/lib/context/SimpleContext.java deleted file mode 100644 index cac83824f..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/context/SimpleContext.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.jozufozu.flywheel.lib.context; - -import java.util.function.Consumer; - -import com.jozufozu.flywheel.api.context.Context; -import com.jozufozu.flywheel.backend.gl.shader.GlProgram; - -import net.minecraft.resources.ResourceLocation; - -public record SimpleContext(ResourceLocation vertexShader, ResourceLocation fragmentShader, Consumer onLink) implements Context { - @Override - public void onProgramLink(GlProgram program) { - onLink.accept(program); - } - - @Override - public ResourceLocation vertexShader() { - return vertexShader; - } - - @Override - public ResourceLocation fragmentShader() { - return fragmentShader; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/context/SimpleContextShader.java b/src/main/java/com/jozufozu/flywheel/lib/context/SimpleContextShader.java new file mode 100644 index 000000000..a14009894 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/context/SimpleContextShader.java @@ -0,0 +1,18 @@ +package com.jozufozu.flywheel.lib.context; + +import com.jozufozu.flywheel.api.context.ContextShader; + +import net.minecraft.resources.ResourceLocation; + +public record SimpleContextShader(ResourceLocation vertexShader, + ResourceLocation fragmentShader) implements ContextShader { + @Override + public ResourceLocation vertexShader() { + return vertexShader; + } + + @Override + public ResourceLocation fragmentShader() { + return fragmentShader; + } +} diff --git a/src/main/resources/flywheel.backend.mixins.json b/src/main/resources/flywheel.backend.mixins.json index 07bbade87..c5948b498 100644 --- a/src/main/resources/flywheel.backend.mixins.json +++ b/src/main/resources/flywheel.backend.mixins.json @@ -6,6 +6,8 @@ "refmap": "flywheel.refmap.json", "client": [ "GlStateManagerMixin", + "LightTextureAccessor", + "OverlayTextureAccessor", "RenderSystemMixin" ], "injectors": {