diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java index 9e6d80268..7cdeeb4d3 100644 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java @@ -50,12 +50,12 @@ public final class FixedWidthFontRenderer { } - private static float toGreyscale( double[] rgb ) + public static float toGreyscale( double[] rgb ) { return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3); } - private static int getColour( char c, Colour def ) + public static int getColour( char c, Colour def ) { return 15 - Terminal.getColour( c, def ); } diff --git a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java new file mode 100644 index 000000000..5d4a43043 --- /dev/null +++ b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java @@ -0,0 +1,176 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.client.render; + +import com.google.common.base.Strings; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.client.gui.FixedWidthFontRenderer; +import dan200.computercraft.shared.util.Palette; +import net.minecraft.client.renderer.OpenGlHelper; +import org.apache.commons.io.IOUtils; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL20; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; + +class MonitorTextureBufferShader +{ + static final int TEXTURE_INDEX = GL13.GL_TEXTURE3; + + private static final FloatBuffer MATRIX_BUFFER = BufferUtils.createFloatBuffer( 16 ); + private static final FloatBuffer PALETTE_BUFFER = BufferUtils.createFloatBuffer( 16 * 3 ); + + private static int uniformMv; + private static int uniformP; + + private static int uniformFont; + private static int uniformWidth; + private static int uniformHeight; + private static int uniformTbo; + private static int uniformPalette; + + private static boolean initialised; + private static boolean ok; + private static int program; + + static void setupUniform( int width, int height, Palette palette, boolean greyscale ) + { + MATRIX_BUFFER.rewind(); + GL11.glGetFloat( GL11.GL_MODELVIEW_MATRIX, MATRIX_BUFFER ); + MATRIX_BUFFER.rewind(); + OpenGlHelper.glUniformMatrix4( uniformMv, false, MATRIX_BUFFER ); + + MATRIX_BUFFER.rewind(); + GL11.glGetFloat( GL11.GL_PROJECTION_MATRIX, MATRIX_BUFFER ); + MATRIX_BUFFER.rewind(); + OpenGlHelper.glUniformMatrix4( uniformP, false, MATRIX_BUFFER ); + + OpenGlHelper.glUniform1i( uniformWidth, width ); + OpenGlHelper.glUniform1i( uniformHeight, height ); + + PALETTE_BUFFER.rewind(); + for( int i = 0; i < 16; i++ ) + { + double[] colour = palette.getColour( i ); + if( greyscale ) + { + float f = FixedWidthFontRenderer.toGreyscale( colour ); + PALETTE_BUFFER.put( f ).put( f ).put( f ); + } + else + { + PALETTE_BUFFER.put( (float) colour[0] ).put( (float) colour[1] ).put( (float) colour[2] ); + } + } + PALETTE_BUFFER.flip(); + OpenGlHelper.glUniform3( uniformPalette, PALETTE_BUFFER ); + } + + static boolean use() + { + if( initialised ) + { + if( ok ) OpenGlHelper.glUseProgram( program ); + return ok; + } + + if( ok = load() ) + { + GL20.glUseProgram( program ); + OpenGlHelper.glUniform1i( uniformFont, 0 ); + OpenGlHelper.glUniform1i( uniformTbo, TEXTURE_INDEX - GL13.GL_TEXTURE0 ); + } + + return ok; + } + + private static boolean load() + { + initialised = true; + + try + { + int vertexShader = loadShader( GL20.GL_VERTEX_SHADER, "assets/computercraft/shaders/monitor.vert" ); + int fragmentShader = loadShader( GL20.GL_FRAGMENT_SHADER, "assets/computercraft/shaders/monitor.frag" ); + + program = OpenGlHelper.glCreateProgram(); + OpenGlHelper.glAttachShader( program, vertexShader ); + OpenGlHelper.glAttachShader( program, fragmentShader ); + GL20.glBindAttribLocation( program, 0, "v_pos" ); + + OpenGlHelper.glLinkProgram( program ); + boolean ok = OpenGlHelper.glGetProgrami( program, GL20.GL_LINK_STATUS ) != 0; + String log = OpenGlHelper.glGetProgramInfoLog( program, Short.MAX_VALUE ).trim(); + if( !Strings.isNullOrEmpty( log ) ) + { + ComputerCraft.log.warn( "Problems when linking monitor shader: {}", log ); + } + + GL20.glDetachShader( program, vertexShader ); + GL20.glDetachShader( program, fragmentShader ); + OpenGlHelper.glDeleteShader( vertexShader ); + OpenGlHelper.glDeleteShader( fragmentShader ); + + if( !ok ) return false; + + uniformMv = getUniformLocation( program, "u_mv" ); + uniformP = getUniformLocation( program, "u_p" ); + + uniformFont = getUniformLocation( program, "u_font" ); + uniformWidth = getUniformLocation( program, "u_width" ); + uniformHeight = getUniformLocation( program, "u_height" ); + uniformTbo = getUniformLocation( program, "u_tbo" ); + uniformPalette = getUniformLocation( program, "u_palette" ); + + ComputerCraft.log.info( "Loaded monitor shader." ); + return true; + } + catch( Exception e ) + { + ComputerCraft.log.error( "Cannot load monitor shaders", e ); + return false; + } + } + + private static int loadShader( int kind, String path ) throws IOException + { + InputStream stream = TileEntityMonitorRenderer.class.getClassLoader().getResourceAsStream( path ); + if( stream == null ) throw new IllegalArgumentException( "Cannot find " + path ); + byte[] contents = IOUtils.toByteArray( new BufferedInputStream( stream ) ); + ByteBuffer buffer = BufferUtils.createByteBuffer( contents.length ); + buffer.put( contents ); + buffer.position( 0 ); + + int shader = OpenGlHelper.glCreateShader( kind ); + + OpenGlHelper.glShaderSource( shader, buffer ); + OpenGlHelper.glCompileShader( shader ); + + boolean ok = OpenGlHelper.glGetShaderi( shader, GL20.GL_COMPILE_STATUS ) != 0; + String log = OpenGlHelper.glGetShaderInfoLog( shader, Short.MAX_VALUE ).trim(); + if( !Strings.isNullOrEmpty( log ) ) + { + ComputerCraft.log.warn( "Problems when loading monitor shader {}: {}", path, log ); + } + + if( !ok ) throw new IllegalStateException( "Cannot compile shader " + path ); + return shader; + } + + private static int getUniformLocation( int program, String name ) + { + int uniform = OpenGlHelper.glGetUniformLocation( program, name ); + if( uniform == -1 ) throw new IllegalStateException( "Cannot find uniform " + name ); + return uniform; + } +} diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index db7f7b785..405a36a29 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -8,23 +8,28 @@ package dan200.computercraft.client.render; import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; +import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.DirectionUtil; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.OpenGlHelper; -import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.VertexBuffer; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL31; import javax.annotation.Nonnull; +import java.nio.ByteBuffer; +import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*; import static dan200.computercraft.shared.peripheral.monitor.TileMonitor.RENDER_MARGIN; public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer @@ -97,8 +102,8 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer