From 0c4fd2b29edf474abf9c22151210c7bdd3775a77 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 9 Nov 2022 21:05:27 +0000 Subject: [PATCH] Make the shader mod system a little more flexible Mostly for multi-loader support, but also /technically/ makes it easier to support multiple loaders in the future. --- .../dan200/computercraft/impl/Services.java | 20 +++--- .../integration/IrisShaderMod.java} | 31 ++++----- .../integration/Optifine.java | 2 +- .../client/integration/ShaderMod.java | 67 +++++++++++++++++++ .../render/TileEntityMonitorRenderer.java | 10 +-- .../peripheral/monitor/TileMonitor.java | 1 + 6 files changed, 94 insertions(+), 37 deletions(-) rename src/main/java/dan200/computercraft/{shared/integration/ShaderMod.java => client/integration/IrisShaderMod.java} (76%) rename src/main/java/dan200/computercraft/{shared => client}/integration/Optifine.java (93%) create mode 100644 src/main/java/dan200/computercraft/client/integration/ShaderMod.java diff --git a/projects/common-api/src/main/java/dan200/computercraft/impl/Services.java b/projects/common-api/src/main/java/dan200/computercraft/impl/Services.java index e7a7a0f13..6bdd30b53 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/impl/Services.java +++ b/projects/common-api/src/main/java/dan200/computercraft/impl/Services.java @@ -8,8 +8,6 @@ package dan200.computercraft.impl; import org.jetbrains.annotations.ApiStatus; import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.List; import java.util.ServiceLoader; import java.util.stream.Collectors; @@ -32,17 +30,15 @@ public final class Services { * @throws IllegalStateException When the service cannot be loaded. */ public static T load(Class klass) { - List services = new ArrayList<>(1); - for (var provider : ServiceLoader.load(klass)) services.add(provider); - switch (services.size()) { - case 1: - return services.get(0); - case 0: - throw new IllegalStateException("Cannot find service for " + klass.getName()); - default: - var serviceTypes = services.stream().map(x -> x.getClass().getName()).collect(Collectors.joining(", ")); + var services = ServiceLoader.load(klass).stream().toList(); + return switch (services.size()) { + case 1 -> services.get(0).get(); + case 0 -> throw new IllegalStateException("Cannot find service for " + klass.getName()); + default -> { + var serviceTypes = services.stream().map(x -> x.type().getName()).collect(Collectors.joining(", ")); throw new IllegalStateException("Multiple services for " + klass.getName() + ": " + serviceTypes); - } + } + }; } /** diff --git a/src/main/java/dan200/computercraft/shared/integration/ShaderMod.java b/src/main/java/dan200/computercraft/client/integration/IrisShaderMod.java similarity index 76% rename from src/main/java/dan200/computercraft/shared/integration/ShaderMod.java rename to src/main/java/dan200/computercraft/client/integration/IrisShaderMod.java index 8c3d3fb12..aaa0b92e2 100644 --- a/src/main/java/dan200/computercraft/shared/integration/ShaderMod.java +++ b/src/main/java/dan200/computercraft/client/integration/IrisShaderMod.java @@ -3,8 +3,9 @@ * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ -package dan200.computercraft.shared.integration; +package dan200.computercraft.client.integration; +import com.google.auto.service.AutoService; import com.mojang.blaze3d.vertex.VertexFormat; import dan200.computercraft.client.render.RenderTypes; import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer; @@ -13,28 +14,20 @@ import net.irisshaders.iris.api.v0.IrisTextVertexSink; import net.minecraftforge.fml.ModList; import java.nio.ByteBuffer; +import java.util.Optional; import java.util.function.IntFunction; -public class ShaderMod { - public static final ShaderMod INSTANCE - = ModList.get().isLoaded("oculus") ? new IrisImpl() - : new ShaderMod(); - - public boolean isShaderMod() { - return Optifine.isLoaded(); +/** + * A {@link ShaderMod} for Oculus (the Forge Iris port). + */ +@AutoService(ShaderMod.Provider.class) +public class IrisShaderMod implements ShaderMod.Provider { + @Override + public Optional get() { + return ModList.get().isLoaded("oculus") ? Optional.of(new Impl()) : Optional.empty(); } - public boolean isRenderingShadowPass() { - return false; - } - - public DirectFixedWidthFontRenderer.QuadEmitter getQuadEmitter(int vertexCount, IntFunction makeBuffer) { - return new DirectFixedWidthFontRenderer.ByteBufferEmitter( - makeBuffer.apply(RenderTypes.TERMINAL.format().getVertexSize() * vertexCount * 4) - ); - } - - private static final class IrisImpl extends ShaderMod { + private static final class Impl extends ShaderMod { @Override public boolean isRenderingShadowPass() { return IrisApi.getInstance().isRenderingShadowPass(); diff --git a/src/main/java/dan200/computercraft/shared/integration/Optifine.java b/src/main/java/dan200/computercraft/client/integration/Optifine.java similarity index 93% rename from src/main/java/dan200/computercraft/shared/integration/Optifine.java rename to src/main/java/dan200/computercraft/client/integration/Optifine.java index 71723edac..f5cd96ffe 100644 --- a/src/main/java/dan200/computercraft/shared/integration/Optifine.java +++ b/src/main/java/dan200/computercraft/client/integration/Optifine.java @@ -3,7 +3,7 @@ * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ -package dan200.computercraft.shared.integration; +package dan200.computercraft.client.integration; /** * Detect whether Optifine is installed. diff --git a/src/main/java/dan200/computercraft/client/integration/ShaderMod.java b/src/main/java/dan200/computercraft/client/integration/ShaderMod.java new file mode 100644 index 000000000..433b29ace --- /dev/null +++ b/src/main/java/dan200/computercraft/client/integration/ShaderMod.java @@ -0,0 +1,67 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.client.integration; + +import dan200.computercraft.client.render.RenderTypes; +import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer; +import dan200.computercraft.client.util.DirectVertexBuffer; + +import java.nio.ByteBuffer; +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.function.IntFunction; + +/** + * Find the currently loaded shader mod (if present) and provides utilities for interacting with it. + */ +public class ShaderMod { + public static ShaderMod get() { + return Storage.INSTANCE; + } + + /** + * Determine if shaders may be used in the current session. + * + * @return Whether a shader mod is loaded. + */ + public boolean isShaderMod() { + return Optifine.isLoaded(); + } + + /** + * Check whether we're currently rendering shadows. Rendering may fall back to a faster but less detailed pass. + * + * @return Whether we're rendering shadows. + */ + public boolean isRenderingShadowPass() { + return false; + } + + /** + * Get an appropriate quad emitter for use with {@link DirectVertexBuffer} and {@link DirectFixedWidthFontRenderer} . + * + * @param vertexCount The number of vertices. + * @param makeBuffer A function to allocate a temporary buffer. + * @return The quad emitter. + */ + public DirectFixedWidthFontRenderer.QuadEmitter getQuadEmitter(int vertexCount, IntFunction makeBuffer) { + return new DirectFixedWidthFontRenderer.ByteBufferEmitter( + makeBuffer.apply(RenderTypes.TERMINAL.format().getVertexSize() * vertexCount * 4) + ); + } + + public interface Provider { + Optional get(); + } + + private static class Storage { + static final ShaderMod INSTANCE = ServiceLoader.load(Provider.class) + .stream() + .flatMap(x -> x.get().get().stream()) + .findFirst() + .orElseGet(ShaderMod::new); + } +} diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index 2100e3a7b..10643f609 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -16,6 +16,7 @@ import com.mojang.math.Matrix3f; import com.mojang.math.Matrix4f; import com.mojang.math.Vector3f; import dan200.computercraft.client.FrameInfo; +import dan200.computercraft.client.integration.ShaderMod; import dan200.computercraft.client.render.monitor.MonitorRenderState; import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer; import dan200.computercraft.client.render.text.FixedWidthFontRenderer; @@ -23,7 +24,6 @@ import dan200.computercraft.client.util.DirectBuffers; import dan200.computercraft.client.util.DirectVertexBuffer; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.config.Config; -import dan200.computercraft.shared.integration.ShaderMod; import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; @@ -112,7 +112,7 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer draw) { - var sink = ShaderMod.INSTANCE.getQuadEmitter(size, TileEntityMonitorRenderer::getBuffer); + var sink = ShaderMod.get().getQuadEmitter(size, TileEntityMonitorRenderer::getBuffer); var buffer = sink.buffer(); draw.accept(sink); @@ -279,8 +279,8 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer