mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 13:42:59 +00:00 
			
		
		
		
	Add a monitor renderer using TBOs (#443)
This uses the system described in #409, to render monitors in a more efficient manner. Each monitor is backed by a texture buffer object (TBO) which contains a relatively compact encoding of the terminal state. This is then rendered using a shader, which consumes the TBO and uses it to index into main font texture. As we're transmitting significantly less data to the GPU (only 3 bytes per character), this effectively reduces any update lag to 0. FPS appears to be up by a small fraction (10-15fps on my machine, to ~110), possibly as we're now only drawing a single quad (though doing much more work in the shader). On my laptop, with its Intel integrated graphics card, I'm able to draw 120 full-sized monitors (with an effective resolution of 3972 x 2330) at a consistent 60fps. Updates still cause a slight spike, but we always remain above 30fps - a significant improvement over VBOs, where updates would go off the chart. Many thanks to @Lignum and @Lemmmy for devising this scheme, and helping test and review it! ♥
This commit is contained in:
		| @@ -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); |         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 ); |         return 15 - Terminal.getColour( c, def ); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -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; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -8,23 +8,28 @@ package dan200.computercraft.client.render; | |||||||
| import dan200.computercraft.client.FrameInfo; | import dan200.computercraft.client.FrameInfo; | ||||||
| import dan200.computercraft.client.gui.FixedWidthFontRenderer; | import dan200.computercraft.client.gui.FixedWidthFontRenderer; | ||||||
| import dan200.computercraft.core.terminal.Terminal; | 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.ClientMonitor; | ||||||
| import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; | import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; | ||||||
| import dan200.computercraft.shared.peripheral.monitor.TileMonitor; | import dan200.computercraft.shared.peripheral.monitor.TileMonitor; | ||||||
|  | import dan200.computercraft.shared.util.Colour; | ||||||
| import dan200.computercraft.shared.util.DirectionUtil; | import dan200.computercraft.shared.util.DirectionUtil; | ||||||
| import net.minecraft.client.Minecraft; | import net.minecraft.client.Minecraft; | ||||||
| import net.minecraft.client.renderer.BufferBuilder; | import net.minecraft.client.renderer.*; | ||||||
| import net.minecraft.client.renderer.GlStateManager; |  | ||||||
| import net.minecraft.client.renderer.OpenGlHelper; |  | ||||||
| import net.minecraft.client.renderer.Tessellator; |  | ||||||
| import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; | import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; | ||||||
|  | import net.minecraft.client.renderer.vertex.DefaultVertexFormats; | ||||||
| import net.minecraft.client.renderer.vertex.VertexBuffer; | import net.minecraft.client.renderer.vertex.VertexBuffer; | ||||||
| import net.minecraft.util.EnumFacing; | import net.minecraft.util.EnumFacing; | ||||||
| import net.minecraft.util.math.BlockPos; | import net.minecraft.util.math.BlockPos; | ||||||
| import org.lwjgl.opengl.GL11; | 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 javax.annotation.Nonnull; | ||||||
|  | import java.nio.ByteBuffer; | ||||||
|  |  | ||||||
|  | import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*; | ||||||
| import static dan200.computercraft.shared.peripheral.monitor.TileMonitor.RENDER_MARGIN; | import static dan200.computercraft.shared.peripheral.monitor.TileMonitor.RENDER_MARGIN; | ||||||
|  |  | ||||||
| public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMonitor> | public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMonitor> | ||||||
| @@ -97,8 +102,8 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon | |||||||
|         if( terminal != null ) |         if( terminal != null ) | ||||||
|         { |         { | ||||||
|             // Draw a terminal |             // Draw a terminal | ||||||
|             double xScale = xSize / (terminal.getWidth() * FixedWidthFontRenderer.FONT_WIDTH); |             double xScale = xSize / (terminal.getWidth() * FONT_WIDTH); | ||||||
|             double yScale = ySize / (terminal.getHeight() * FixedWidthFontRenderer.FONT_HEIGHT); |             double yScale = ySize / (terminal.getHeight() * FONT_HEIGHT); | ||||||
|  |  | ||||||
|             GlStateManager.pushMatrix(); |             GlStateManager.pushMatrix(); | ||||||
|             GlStateManager.scale( (float) xScale, (float) -yScale, 1.0f ); |             GlStateManager.scale( (float) xScale, (float) -yScale, 1.0f ); | ||||||
| @@ -147,6 +152,52 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon | |||||||
|  |  | ||||||
|         switch( renderer ) |         switch( renderer ) | ||||||
|         { |         { | ||||||
|  |             case TBO: | ||||||
|  |             { | ||||||
|  |                 if( !MonitorTextureBufferShader.use() ) return; | ||||||
|  |  | ||||||
|  |                 Terminal terminal = monitor.getTerminal(); | ||||||
|  |                 int width = terminal.getWidth(), height = terminal.getHeight(); | ||||||
|  |                 int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT; | ||||||
|  |  | ||||||
|  |                 if( redraw ) | ||||||
|  |                 { | ||||||
|  |                     ByteBuffer monitorBuffer = GLAllocation.createDirectByteBuffer( width * height * 3 ); | ||||||
|  |                     for( int y = 0; y < height; y++ ) | ||||||
|  |                     { | ||||||
|  |                         TextBuffer text = terminal.getLine( y ), textColour = terminal.getTextColourLine( y ), background = terminal.getBackgroundColourLine( y ); | ||||||
|  |                         for( int x = 0; x < width; x++ ) | ||||||
|  |                         { | ||||||
|  |                             monitorBuffer.put( (byte) (text.charAt( x ) & 0xFF) ); | ||||||
|  |                             monitorBuffer.put( (byte) getColour( textColour.charAt( x ), Colour.White ) ); | ||||||
|  |                             monitorBuffer.put( (byte) getColour( background.charAt( x ), Colour.Black ) ); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     monitorBuffer.flip(); | ||||||
|  |  | ||||||
|  |                     OpenGlHelper.glBindBuffer( GL31.GL_TEXTURE_BUFFER, monitor.tboBuffer ); | ||||||
|  |                     OpenGlHelper.glBufferData( GL31.GL_TEXTURE_BUFFER, monitorBuffer, GL15.GL_STATIC_DRAW ); | ||||||
|  |                     OpenGlHelper.glBindBuffer( GL31.GL_TEXTURE_BUFFER, 0 ); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // Bind TBO texture and set up the uniforms. We've already set up the main font above. | ||||||
|  |                 GlStateManager.setActiveTexture( MonitorTextureBufferShader.TEXTURE_INDEX ); | ||||||
|  |                 GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, monitor.tboTexture ); | ||||||
|  |                 GlStateManager.setActiveTexture( GL13.GL_TEXTURE0 ); | ||||||
|  |  | ||||||
|  |                 MonitorTextureBufferShader.setupUniform( width, height, terminal.getPalette(), !monitor.isColour() ); | ||||||
|  |  | ||||||
|  |                 buffer.begin( GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION ); | ||||||
|  |                 buffer.pos( -xMargin, -yMargin, 0 ).endVertex(); | ||||||
|  |                 buffer.pos( -xMargin, pixelHeight + yMargin, 0 ).endVertex(); | ||||||
|  |                 buffer.pos( pixelWidth + xMargin, -yMargin, 0 ).endVertex(); | ||||||
|  |                 buffer.pos( pixelWidth + xMargin, pixelHeight + yMargin, 0 ).endVertex(); | ||||||
|  |                 tessellator.draw(); | ||||||
|  |  | ||||||
|  |                 OpenGlHelper.glUseProgram( 0 ); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             case VBO: |             case VBO: | ||||||
|             { |             { | ||||||
|                 VertexBuffer vbo = monitor.buffer; |                 VertexBuffer vbo = monitor.buffer; | ||||||
|   | |||||||
| @@ -8,10 +8,16 @@ package dan200.computercraft.shared.peripheral.monitor; | |||||||
| import dan200.computercraft.client.gui.FixedWidthFontRenderer; | import dan200.computercraft.client.gui.FixedWidthFontRenderer; | ||||||
| import dan200.computercraft.shared.common.ClientTerminal; | import dan200.computercraft.shared.common.ClientTerminal; | ||||||
| import net.minecraft.client.renderer.GLAllocation; | import net.minecraft.client.renderer.GLAllocation; | ||||||
|  | import net.minecraft.client.renderer.GlStateManager; | ||||||
|  | import net.minecraft.client.renderer.OpenGlHelper; | ||||||
| import net.minecraft.client.renderer.vertex.VertexBuffer; | import net.minecraft.client.renderer.vertex.VertexBuffer; | ||||||
| import net.minecraft.util.math.BlockPos; | import net.minecraft.util.math.BlockPos; | ||||||
| import net.minecraftforge.fml.relauncher.Side; | import net.minecraftforge.fml.relauncher.Side; | ||||||
| import net.minecraftforge.fml.relauncher.SideOnly; | import net.minecraftforge.fml.relauncher.SideOnly; | ||||||
|  | import org.lwjgl.opengl.GL11; | ||||||
|  | import org.lwjgl.opengl.GL15; | ||||||
|  | import org.lwjgl.opengl.GL30; | ||||||
|  | import org.lwjgl.opengl.GL31; | ||||||
|  |  | ||||||
| import java.util.HashSet; | import java.util.HashSet; | ||||||
| import java.util.Iterator; | import java.util.Iterator; | ||||||
| @@ -26,6 +32,8 @@ public final class ClientMonitor extends ClientTerminal | |||||||
|     public long lastRenderFrame = -1; |     public long lastRenderFrame = -1; | ||||||
|     public BlockPos lastRenderPos = null; |     public BlockPos lastRenderPos = null; | ||||||
|  |  | ||||||
|  |     public int tboBuffer; | ||||||
|  |     public int tboTexture; | ||||||
|     public VertexBuffer buffer; |     public VertexBuffer buffer; | ||||||
|     public int displayList = 0; |     public int displayList = 0; | ||||||
|  |  | ||||||
| @@ -43,7 +51,7 @@ public final class ClientMonitor extends ClientTerminal | |||||||
|     /** |     /** | ||||||
|      * Create the appropriate buffer if needed. |      * Create the appropriate buffer if needed. | ||||||
|      * |      * | ||||||
|      * @param renderer The renderer to use. This can be fetched from {@link #renderer()}. |      * @param renderer The renderer to use. This can be fetched from {@link MonitorRenderer#current()}. | ||||||
|      * @return If a buffer was created. This will return {@code false} if we already have an appropriate buffer, |      * @return If a buffer was created. This will return {@code false} if we already have an appropriate buffer, | ||||||
|      * or this mode does not require one. |      * or this mode does not require one. | ||||||
|      */ |      */ | ||||||
| @@ -52,6 +60,26 @@ public final class ClientMonitor extends ClientTerminal | |||||||
|     { |     { | ||||||
|         switch( renderer ) |         switch( renderer ) | ||||||
|         { |         { | ||||||
|  |             case TBO: | ||||||
|  |             { | ||||||
|  |                 if( tboBuffer != 0 ) return false; | ||||||
|  |  | ||||||
|  |                 deleteBuffers(); | ||||||
|  |  | ||||||
|  |                 tboBuffer = OpenGlHelper.glGenBuffers(); | ||||||
|  |                 OpenGlHelper.glBindBuffer( GL31.GL_TEXTURE_BUFFER, tboBuffer ); | ||||||
|  |                 GL15.glBufferData( GL31.GL_TEXTURE_BUFFER, 0, GL15.GL_STATIC_DRAW ); | ||||||
|  |                 tboTexture = GlStateManager.generateTexture(); | ||||||
|  |                 GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, tboTexture ); | ||||||
|  |                 GL31.glTexBuffer( GL31.GL_TEXTURE_BUFFER, GL30.GL_R8, tboBuffer ); | ||||||
|  |                 GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, 0 ); | ||||||
|  |  | ||||||
|  |                 OpenGlHelper.glBindBuffer( GL31.GL_TEXTURE_BUFFER, 0 ); | ||||||
|  |  | ||||||
|  |                 addMonitor(); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |  | ||||||
|             case VBO: |             case VBO: | ||||||
|                 if( buffer != null ) return false; |                 if( buffer != null ) return false; | ||||||
|  |  | ||||||
| @@ -59,6 +87,7 @@ public final class ClientMonitor extends ClientTerminal | |||||||
|                 buffer = new VertexBuffer( FixedWidthFontRenderer.POSITION_COLOR_TEX ); |                 buffer = new VertexBuffer( FixedWidthFontRenderer.POSITION_COLOR_TEX ); | ||||||
|                 addMonitor(); |                 addMonitor(); | ||||||
|                 return true; |                 return true; | ||||||
|  |  | ||||||
|             case DISPLAY_LIST: |             case DISPLAY_LIST: | ||||||
|                 if( displayList != 0 ) return false; |                 if( displayList != 0 ) return false; | ||||||
|  |  | ||||||
| @@ -82,6 +111,19 @@ public final class ClientMonitor extends ClientTerminal | |||||||
|  |  | ||||||
|     private void deleteBuffers() |     private void deleteBuffers() | ||||||
|     { |     { | ||||||
|  |  | ||||||
|  |         if( tboBuffer != 0 ) | ||||||
|  |         { | ||||||
|  |             OpenGlHelper.glDeleteBuffers( tboBuffer ); | ||||||
|  |             tboBuffer = 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if( tboTexture != 0 ) | ||||||
|  |         { | ||||||
|  |             GlStateManager.deleteTexture( tboTexture ); | ||||||
|  |             tboTexture = 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if( buffer != null ) |         if( buffer != null ) | ||||||
|         { |         { | ||||||
|             buffer.deleteGlBuffers(); |             buffer.deleteGlBuffers(); | ||||||
| @@ -98,7 +140,7 @@ public final class ClientMonitor extends ClientTerminal | |||||||
|     @SideOnly( Side.CLIENT ) |     @SideOnly( Side.CLIENT ) | ||||||
|     public void destroy() |     public void destroy() | ||||||
|     { |     { | ||||||
|         if( buffer != null || displayList != 0 ) |         if( tboBuffer != 0 || buffer != null || displayList != 0 ) | ||||||
|         { |         { | ||||||
|             synchronized( allMonitors ) |             synchronized( allMonitors ) | ||||||
|             { |             { | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ package dan200.computercraft.shared.peripheral.monitor; | |||||||
| import dan200.computercraft.ComputerCraft; | import dan200.computercraft.ComputerCraft; | ||||||
| import dan200.computercraft.client.render.TileEntityMonitorRenderer; | import dan200.computercraft.client.render.TileEntityMonitorRenderer; | ||||||
| import net.minecraft.client.renderer.OpenGlHelper; | import net.minecraft.client.renderer.OpenGlHelper; | ||||||
|  | import org.lwjgl.opengl.GLContext; | ||||||
|  |  | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| import java.util.Locale; | import java.util.Locale; | ||||||
| @@ -27,7 +28,14 @@ public enum MonitorRenderer | |||||||
|     BEST, |     BEST, | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Render using VBOs. This is the default when supported. |      * Render using texture buffer objects. | ||||||
|  |      * | ||||||
|  |      * @see org.lwjgl.opengl.GL31#glTexBuffer(int, int, int) | ||||||
|  |      */ | ||||||
|  |     TBO, | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Render using VBOs. | ||||||
|      * |      * | ||||||
|      * @see net.minecraft.client.renderer.vertex.VertexBuffer |      * @see net.minecraft.client.renderer.vertex.VertexBuffer | ||||||
|      */ |      */ | ||||||
| @@ -84,6 +92,16 @@ public enum MonitorRenderer | |||||||
|         { |         { | ||||||
|             case BEST: |             case BEST: | ||||||
|                 return best(); |                 return best(); | ||||||
|  |             case TBO: | ||||||
|  |                 checkCapabilities(); | ||||||
|  |                 if( !textureBuffer ) | ||||||
|  |                 { | ||||||
|  |                     ComputerCraft.log.warn( "Texture buffers are not supported on your graphics card. Falling back to default." ); | ||||||
|  |                     ComputerCraft.monitorRenderer = BEST; | ||||||
|  |                     return best(); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 return TBO; | ||||||
|             case VBO: |             case VBO: | ||||||
|                 if( !OpenGlHelper.vboSupported ) |                 if( !OpenGlHelper.vboSupported ) | ||||||
|                 { |                 { | ||||||
| @@ -100,6 +118,20 @@ public enum MonitorRenderer | |||||||
|  |  | ||||||
|     private static MonitorRenderer best() |     private static MonitorRenderer best() | ||||||
|     { |     { | ||||||
|         return OpenGlHelper.vboSupported ? VBO : DISPLAY_LIST; |         checkCapabilities(); | ||||||
|  |         if( textureBuffer ) return TBO; | ||||||
|  |         if( OpenGlHelper.vboSupported ) return VBO; | ||||||
|  |         return DISPLAY_LIST; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private static boolean initialised = false; | ||||||
|  |     private static boolean textureBuffer = false; | ||||||
|  |  | ||||||
|  |     private static void checkCapabilities() | ||||||
|  |     { | ||||||
|  |         if( initialised ) return; | ||||||
|  |  | ||||||
|  |         textureBuffer = GLContext.getCapabilities().OpenGL31; | ||||||
|  |         initialised = true; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -187,6 +187,7 @@ gui.computercraft:config.peripheral.modem_high_altitude_range_during_storm=Modem | |||||||
| gui.computercraft:config.peripheral.max_notes_per_tick=Maximum notes that a computer can play at once | gui.computercraft:config.peripheral.max_notes_per_tick=Maximum notes that a computer can play at once | ||||||
| gui.computercraft:config.peripheral.monitor_renderer=Monitor renderer | gui.computercraft:config.peripheral.monitor_renderer=Monitor renderer | ||||||
| gui.computercraft:config.peripheral.monitor_renderer.best=Best | gui.computercraft:config.peripheral.monitor_renderer.best=Best | ||||||
|  | gui.computercraft:config.peripheral.monitor_renderer.tbo=Texture Buffers | ||||||
| gui.computercraft:config.peripheral.monitor_renderer.vbo=Vertex Buffers | gui.computercraft:config.peripheral.monitor_renderer.vbo=Vertex Buffers | ||||||
| gui.computercraft:config.peripheral.monitor_renderer.display_list=Display Lists | gui.computercraft:config.peripheral.monitor_renderer.display_list=Display Lists | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										40
									
								
								src/main/resources/assets/computercraft/shaders/monitor.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/main/resources/assets/computercraft/shaders/monitor.frag
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | #version 140 | ||||||
|  |  | ||||||
|  | #define FONT_WIDTH 6.0 | ||||||
|  | #define FONT_HEIGHT 9.0 | ||||||
|  |  | ||||||
|  | uniform sampler2D u_font; | ||||||
|  | uniform int u_width; | ||||||
|  | uniform int u_height; | ||||||
|  | uniform samplerBuffer u_tbo; | ||||||
|  | uniform vec3 u_palette[16]; | ||||||
|  |  | ||||||
|  | in vec2 f_pos; | ||||||
|  |  | ||||||
|  | out vec4 colour; | ||||||
|  |  | ||||||
|  | vec2 texture_corner(int index) { | ||||||
|  |     float x = 1.0 + float(index % 16) * (FONT_WIDTH + 2.0); | ||||||
|  |     float y = 1.0 + float(index / 16) * (FONT_HEIGHT + 2.0); | ||||||
|  |     return vec2(x, y); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void main() { | ||||||
|  |     vec2 term_pos = vec2(f_pos.x / FONT_WIDTH, f_pos.y / FONT_HEIGHT); | ||||||
|  |     vec2 corner = floor(term_pos); | ||||||
|  |  | ||||||
|  |     ivec2 cell = ivec2(corner); | ||||||
|  |     int index = 3 * (clamp(cell.x, 0, u_width - 1) + clamp(cell.y, 0, u_height - 1) * u_width); | ||||||
|  |  | ||||||
|  |     // 1 if 0 <= x, y < width, height, 0 otherwise | ||||||
|  |     vec2 outside = step(vec2(0.0, 0.0), vec2(cell)) * step(vec2(cell), vec2(float(u_width) - 1.0, float(u_height) - 1.0)); | ||||||
|  |     float mult = outside.x * outside.y; | ||||||
|  |  | ||||||
|  |     int character = int(texelFetch(u_tbo, index).r * 255.0); | ||||||
|  |     int fg = int(texelFetch(u_tbo, index + 1).r * 255.0); | ||||||
|  |     int bg = int(texelFetch(u_tbo, index + 2).r * 255.0); | ||||||
|  |  | ||||||
|  |     vec2 pos = (term_pos - corner) * vec2(FONT_WIDTH, FONT_HEIGHT); | ||||||
|  |     vec4 img = texture2D(u_font, (texture_corner(character) + pos) / 256.0); | ||||||
|  |     colour = vec4(mix(u_palette[bg], img.rgb * u_palette[fg], img.a * mult), 1.0); | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								src/main/resources/assets/computercraft/shaders/monitor.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/main/resources/assets/computercraft/shaders/monitor.vert
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | #version 140 | ||||||
|  |  | ||||||
|  | uniform mat4 u_mv; | ||||||
|  | uniform mat4 u_p; | ||||||
|  |  | ||||||
|  | in vec3 v_pos; | ||||||
|  |  | ||||||
|  | out vec2 f_pos; | ||||||
|  |  | ||||||
|  | void main() { | ||||||
|  |     gl_Position = u_p * u_mv * vec4(v_pos.x, v_pos.y, 0, 1); | ||||||
|  |     f_pos = v_pos.xy; | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Jonathan Coates
					Jonathan Coates