mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-01-12 02:10:30 +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:
parent
1547ecbeb3
commit
70b457ed18
@ -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 );
|
||||
}
|
||||
|
@ -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.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<TileMonitor>
|
||||
@ -97,8 +102,8 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
|
||||
if( terminal != null )
|
||||
{
|
||||
// Draw a terminal
|
||||
double xScale = xSize / (terminal.getWidth() * FixedWidthFontRenderer.FONT_WIDTH);
|
||||
double yScale = ySize / (terminal.getHeight() * FixedWidthFontRenderer.FONT_HEIGHT);
|
||||
double xScale = xSize / (terminal.getWidth() * FONT_WIDTH);
|
||||
double yScale = ySize / (terminal.getHeight() * FONT_HEIGHT);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.scale( (float) xScale, (float) -yScale, 1.0f );
|
||||
@ -147,6 +152,52 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer<TileMon
|
||||
|
||||
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:
|
||||
{
|
||||
VertexBuffer vbo = monitor.buffer;
|
||||
|
@ -8,10 +8,16 @@ package dan200.computercraft.shared.peripheral.monitor;
|
||||
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.shared.common.ClientTerminal;
|
||||
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.util.math.BlockPos;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
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.Iterator;
|
||||
@ -26,6 +32,8 @@ public final class ClientMonitor extends ClientTerminal
|
||||
public long lastRenderFrame = -1;
|
||||
public BlockPos lastRenderPos = null;
|
||||
|
||||
public int tboBuffer;
|
||||
public int tboTexture;
|
||||
public VertexBuffer buffer;
|
||||
public int displayList = 0;
|
||||
|
||||
@ -43,7 +51,7 @@ public final class ClientMonitor extends ClientTerminal
|
||||
/**
|
||||
* 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,
|
||||
* or this mode does not require one.
|
||||
*/
|
||||
@ -52,6 +60,26 @@ public final class ClientMonitor extends ClientTerminal
|
||||
{
|
||||
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:
|
||||
if( buffer != null ) return false;
|
||||
|
||||
@ -59,6 +87,7 @@ public final class ClientMonitor extends ClientTerminal
|
||||
buffer = new VertexBuffer( FixedWidthFontRenderer.POSITION_COLOR_TEX );
|
||||
addMonitor();
|
||||
return true;
|
||||
|
||||
case DISPLAY_LIST:
|
||||
if( displayList != 0 ) return false;
|
||||
|
||||
@ -82,6 +111,19 @@ public final class ClientMonitor extends ClientTerminal
|
||||
|
||||
private void deleteBuffers()
|
||||
{
|
||||
|
||||
if( tboBuffer != 0 )
|
||||
{
|
||||
OpenGlHelper.glDeleteBuffers( tboBuffer );
|
||||
tboBuffer = 0;
|
||||
}
|
||||
|
||||
if( tboTexture != 0 )
|
||||
{
|
||||
GlStateManager.deleteTexture( tboTexture );
|
||||
tboTexture = 0;
|
||||
}
|
||||
|
||||
if( buffer != null )
|
||||
{
|
||||
buffer.deleteGlBuffers();
|
||||
@ -98,7 +140,7 @@ public final class ClientMonitor extends ClientTerminal
|
||||
@SideOnly( Side.CLIENT )
|
||||
public void destroy()
|
||||
{
|
||||
if( buffer != null || displayList != 0 )
|
||||
if( tboBuffer != 0 || buffer != null || displayList != 0 )
|
||||
{
|
||||
synchronized( allMonitors )
|
||||
{
|
||||
|
@ -9,6 +9,7 @@ package dan200.computercraft.shared.peripheral.monitor;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.client.render.TileEntityMonitorRenderer;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import org.lwjgl.opengl.GLContext;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Locale;
|
||||
@ -27,7 +28,14 @@ public enum MonitorRenderer
|
||||
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
|
||||
*/
|
||||
@ -84,6 +92,16 @@ public enum MonitorRenderer
|
||||
{
|
||||
case 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:
|
||||
if( !OpenGlHelper.vboSupported )
|
||||
{
|
||||
@ -100,6 +118,20 @@ public enum MonitorRenderer
|
||||
|
||||
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.monitor_renderer=Monitor renderer
|
||||
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.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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user