diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java index 48a8b6aed..36868c428 100644 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java @@ -409,7 +409,7 @@ public final class FixedWidthFontRenderer false, false ) ) // blur, minimap .alpha( ONE_TENTH_ALPHA ) - .writeMaskState( DEPTH_MASK ) + .writeMaskState( ALL_MASK ) .lightmap( DISABLE_LIGHTMAP ) .build( false ) ); diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index 5390b812a..2c40576e4 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -59,10 +59,7 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer // Render from the origin monitor ClientMonitor originTerminal = monitor.getClientMonitor(); - if( originTerminal == null ) - { - return; - } + if( originTerminal == null ) return; TileMonitor origin = originTerminal.getOrigin(); BlockPos monitorPos = monitor.getPos(); @@ -96,10 +93,21 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer transform.multiply( Vector3f.POSITIVE_X.getDegreesQuaternion( pitch ) ); transform.translate( -0.5 + TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN, origin.getHeight() - 0.5 - (TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN) + 0, - 0.5 ); + 0.50 ); double xSize = origin.getWidth() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER); double ySize = origin.getHeight() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER); + // Draw the background blocker + FixedWidthFontRenderer.drawBlocker( transform.peek().getModel(), + renderer, + (float) -TileMonitor.RENDER_MARGIN, + (float) TileMonitor.RENDER_MARGIN, + (float) (xSize + 2 * TileMonitor.RENDER_MARGIN), + (float) -(ySize + TileMonitor.RENDER_MARGIN * 2) ); + + // Set the contents slightly off the surface to prevent z-fighting + transform.translate( 0.0, 0.0, 0.001 ); + // Draw the contents Terminal terminal = originTerminal.getTerminal(); if( terminal != null ) @@ -112,8 +120,7 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer transform.push(); transform.scale( (float) xScale, (float) -yScale, 1.0f ); - Matrix4f matrix = transform.peek() - .getModel(); + Matrix4f matrix = transform.peek().getModel(); // Sneaky hack here: we get a buffer now in order to flush existing ones and set up the appropriate // render state. I've no clue how well this'll work in future versions of Minecraft, but it does the trick @@ -127,6 +134,10 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer // reasonable. FixedWidthFontRenderer.drawCursor( matrix, buffer, 0, 0, terminal, !originTerminal.isColour() ); + // To go along with sneaky hack above: make sure state changes are undone. I would have thought this would + // happen automatically after these buffers are drawn, but chests will render weird around monitors without this. + FixedWidthFontRenderer.TYPE.endDrawing(); + transform.pop(); } else @@ -140,14 +151,6 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer (float) -(ySize + MARGIN * 2) ); } - FixedWidthFontRenderer.drawBlocker( transform.peek() - .getModel(), - renderer, - (float) -TileMonitor.RENDER_MARGIN, - (float) TileMonitor.RENDER_MARGIN, - (float) (xSize + 2 * TileMonitor.RENDER_MARGIN), - (float) -(ySize + TileMonitor.RENDER_MARGIN * 2) ); - transform.pop(); } diff --git a/src/main/java/dan200/computercraft/shared/integration/ModMenuIntegration.java b/src/main/java/dan200/computercraft/shared/integration/ModMenuIntegration.java index 1455446c9..f973cf5a5 100644 --- a/src/main/java/dan200/computercraft/shared/integration/ModMenuIntegration.java +++ b/src/main/java/dan200/computercraft/shared/integration/ModMenuIntegration.java @@ -7,10 +7,18 @@ package dan200.computercraft.shared.integration; import com.terraformersmc.modmenu.api.ConfigScreenFactory; import com.terraformersmc.modmenu.api.ModMenuApi; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; +import dan200.computercraft.shared.util.Config; +import me.shedaniel.clothconfig2.api.ConfigBuilder; +import me.shedaniel.clothconfig2.api.ConfigCategory; +import me.shedaniel.clothconfig2.api.ConfigEntryBuilder; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; -// A stub modmenu entrypoint for when we get there +// A poor mod menu integration just for testing the monitor rendering changes we've been making :) @Environment( EnvType.CLIENT ) public class ModMenuIntegration implements ModMenuApi @@ -18,6 +26,27 @@ public class ModMenuIntegration implements ModMenuApi @Override public ConfigScreenFactory getModConfigScreenFactory() { - return parent -> null; + return parent -> { + ConfigBuilder builder = ConfigBuilder.create().setParentScreen( parent ) + .setTitle( new LiteralText( "Computer Craft" ) ) + .setSavingRunnable( () -> { + Config.clientSpec.correct( Config.clientConfig ); + Config.sync(); + Config.save(); + ComputerCraft.log.info( "Monitor renderer: {}", ComputerCraft.monitorRenderer ); + } ); + + ConfigCategory client = builder.getOrCreateCategory( new LiteralText( "Client" ) ); + + ConfigEntryBuilder entryBuilder = builder.entryBuilder(); + + client.addEntry( entryBuilder.startEnumSelector( new LiteralText( "Monitor Renderer" ), MonitorRenderer.class, ComputerCraft.monitorRenderer ) + .setDefaultValue( MonitorRenderer.BEST ) + .setSaveConsumer( renderer -> { Config.clientConfig.set( "monitor_renderer", renderer ); } ) + .setTooltip( Text.of( Config.clientConfig.getComment( "monitor_renderer" ) ) ) + .build() ); + + return builder.build(); + }; } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java index 6d0dc360f..90980336e 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java @@ -7,9 +7,12 @@ package dan200.computercraft.shared.peripheral.monitor; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.render.TileEntityMonitorRenderer; +import net.fabricmc.loader.api.FabricLoader; import org.lwjgl.opengl.GL; import javax.annotation.Nonnull; +import java.util.Arrays; +import java.util.List; /** * The render type to use for monitors. @@ -38,6 +41,9 @@ public enum MonitorRenderer private static boolean initialised = false; private static boolean textureBuffer = false; + private static boolean shaderMod = false; + //TODO find out which shader mods do better with VBOs and add them here. + private static List shaderModIds = Arrays.asList( "optifabric" ); /** * Get the current renderer to use. @@ -69,18 +75,30 @@ public enum MonitorRenderer private static MonitorRenderer best() { - checkCapabilities(); - return textureBuffer ? TBO : VBO; + if ( !initialised ) + { + checkCapabilities(); + checkForShaderMods(); + if ( textureBuffer && shaderMod ) + { + ComputerCraft.log.warn( "Shader mod detected. Enabling VBO renderer for compatibility." ); + } + + initialised = true; + } + + return textureBuffer && !shaderMod ? TBO : VBO; } private static void checkCapabilities() { - if( initialised ) - { - return; - } - textureBuffer = GL.getCapabilities().OpenGL31; - initialised = true; + } + + private static void checkForShaderMods() + { + shaderMod = FabricLoader.getInstance().getAllMods().stream() + .map( modContainer -> modContainer.getMetadata().getId() ) + .anyMatch( id -> shaderModIds.contains( id ) ); } } diff --git a/src/main/java/dan200/computercraft/shared/util/Config.java b/src/main/java/dan200/computercraft/shared/util/Config.java index a6b14af07..06dd19fac 100644 --- a/src/main/java/dan200/computercraft/shared/util/Config.java +++ b/src/main/java/dan200/computercraft/shared/util/Config.java @@ -5,7 +5,6 @@ */ package dan200.computercraft.shared.util; -import com.electronwill.nightconfig.core.CommentedConfig; import com.electronwill.nightconfig.core.ConfigSpec; import com.electronwill.nightconfig.core.EnumGetMethod; import com.electronwill.nightconfig.core.UnmodifiableConfig; @@ -39,11 +38,13 @@ public final class Config public static final CommentedConfigSpec serverSpec; public static final CommentedConfigSpec clientSpec; - public static CommentedConfig serverConfig; - public static CommentedConfig clientConfig; + public static CommentedFileConfig serverConfig; + public static CommentedFileConfig clientConfig; private static final WorldSavePath serverDir = WorldSavePathAccess.createWorldSavePath( "serverconfig" ); private static final String serverFileName = "computercraft-server.toml"; + + private static Path serverPath = null; private static final Path clientPath = FabricLoader.INSTANCE.getConfigDir().resolve( "computercraft-client.toml" ); private Config() @@ -243,7 +244,7 @@ public final class Config clientSpec.defineInRange( "monitor_distance", 64, 16, 1024 ); } - private static final FileNotFoundAction MAKE_DIRECTORIES = ( file, configFormat ) -> { + private static final FileNotFoundAction MAKE_DIRECTORIES_AND_FILE = ( file, configFormat ) -> { Files.createDirectories( file.getParent() ); Files.createFile( file ); configFormat.initEmptyFile( file ); @@ -253,14 +254,36 @@ public final class Config private static CommentedFileConfig buildFileConfig( Path path ) { return CommentedFileConfig.builder( path ) - .onFileNotFound( MAKE_DIRECTORIES ) + .onFileNotFound( MAKE_DIRECTORIES_AND_FILE ) .preserveInsertionOrder() .build(); } + private static void saveConfig( UnmodifiableConfig config, CommentedConfigSpec spec, Path path ) + { + try( CommentedFileConfig fileConfig = buildFileConfig( path ) ) + { + fileConfig.putAll( config ); + spec.correct( fileConfig ); + fileConfig.save(); + } + } + + public static void save() + { + if( clientConfig != null ) + { + saveConfig( clientConfig, clientSpec, clientPath ); + } + if( serverConfig != null && serverPath != null ) + { + saveConfig( serverConfig, serverSpec, serverPath ); + } + } + public static void serverStarting( MinecraftServer server ) { - Path serverPath = server.getSavePath( serverDir ).resolve( serverFileName ); + serverPath = server.getSavePath( serverDir ).resolve( serverFileName ); try( CommentedFileConfig config = buildFileConfig( serverPath ) ) { @@ -275,6 +298,7 @@ public final class Config public static void serverStopping( MinecraftServer server ) { serverConfig = null; + serverPath = null; } public static void clientStarted( MinecraftClient client )