mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-07-08 13:02:54 +00:00
Cleanup and optimise terminal rendering (#1057)
- Remove the POSITION_COLOR render type. Instead we just render a background terminal quad as the pocket computer light - it's a little (lot?) more cheaty, but saves having to create a render type. - Use the existing position_color_tex shader instead of our copy. I looked at using RenderType.text, but had a bunch of problems with GUI terminals. Its possible we can fix it, but didn't want to spend too much time on it. - Remove some methods from FixedWidthFontRenderer, inlining them into the call site. - Switch back to using GL_QUADS rather than GL_TRIANGLES. I know Lig will shout at me for this, but the rest of MC uses QUADS, so I don't think best practice really matters here. - Fix the TBO backend monitor not rendering monitors with fog. Unfortunately we can't easily do this to the VBO one without writing a custom shader (which defeats the whole point of the VBO backend!), as the distance calculation of most render types expect an already-transformed position (camera-relative I think!) while we pass a world-relative one. - When rendering to a VBO we push vertices to a ByteBuffer directly, rather than going through MC's VertexConsumer system. This removes the overhead which comes with VertexConsumer, significantly improving performance. - Pre-convert palette colours to bytes, storing both the coloured and greyscale versions as a byte array. This allows us to remove the multiple casts and conversions (double -> float -> (greyscale) -> byte), offering noticeable performance improvements (multiple ms per frame). We're using a byte[] here rather than a record of three bytes as notionally it provides better performance when writing to a ByteBuffer directly compared to calling .put() four times. [^1] - Memorize getRenderBoundingBox. This was taking about 5% of the total time on the render thread[^2], so worth doing. I don't actually think the allocation is the heavy thing here - VisualVM says it's toWorldPos being slow. I'm not sure why - possibly just all the block property lookups? [^2] Note that none of these changes improve compatibility with Optifine. Right now there's some serious issues where monitors are writing _over_ blocks in front of them. To fix this, we probably need to remove the depth blocker and just render characters with a z offset. Will do that in a separate commit, as I need to evaluate how well that change will work first. The main advantage of this commit is the improved performance. In my stress test with 120 monitors updating every tick, I'm getting 10-20fps [^3] (still much worse than TBOs, which manages a solid 60-100). In practice, we'll actually be much better than this. Our network bandwidth limits means only 40 change in a single tick - and so FPS is much more reasonable (+60fps). [^1]: In general, put(byte[]) is faster than put(byte) multiple times. Just not clear if this is true when dealing with a small (and loop unrolled) number of bytes. [^2]: To be clear, this is with 120 monitors and no other block entities with custom renderers. so not really representative. [^3]: I wish I could provide a narrower range, but it varies so much between me restarting the game. Makes it impossible to benchmark anything!
This commit is contained in:
parent
ba7598c689
commit
41fa95bce4
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package dan200.computercraft.client.gui;
|
package dan200.computercraft.client.gui;
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.Tesselator;
|
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
import com.mojang.math.Matrix4f;
|
import com.mojang.math.Matrix4f;
|
||||||
import dan200.computercraft.client.FrameInfo;
|
import dan200.computercraft.client.FrameInfo;
|
||||||
@ -14,11 +14,11 @@ import dan200.computercraft.core.terminal.Terminal;
|
|||||||
import dan200.computercraft.core.terminal.TextBuffer;
|
import dan200.computercraft.core.terminal.TextBuffer;
|
||||||
import dan200.computercraft.shared.util.Colour;
|
import dan200.computercraft.shared.util.Colour;
|
||||||
import dan200.computercraft.shared.util.Palette;
|
import dan200.computercraft.shared.util.Palette;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
|
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
|
||||||
|
|
||||||
@ -44,15 +44,22 @@ public final class FixedWidthFontRenderer
|
|||||||
|
|
||||||
public static final int FONT_HEIGHT = 9;
|
public static final int FONT_HEIGHT = 9;
|
||||||
public static final int FONT_WIDTH = 6;
|
public static final int FONT_WIDTH = 6;
|
||||||
public static final float WIDTH = 256.0f;
|
private static final float WIDTH = 256.0f;
|
||||||
|
|
||||||
public static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH;
|
private static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH;
|
||||||
public static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH;
|
private static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH;
|
||||||
|
|
||||||
|
private static final byte[] BLACK = new byte[] { byteColour( Colour.BLACK.getR() ), byteColour( Colour.BLACK.getR() ), byteColour( Colour.BLACK.getR() ), (byte) 255 };
|
||||||
|
|
||||||
private FixedWidthFontRenderer()
|
private FixedWidthFontRenderer()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static byte byteColour( float c )
|
||||||
|
{
|
||||||
|
return (byte) (int) (c * 255);
|
||||||
|
}
|
||||||
|
|
||||||
public 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);
|
||||||
@ -63,7 +70,7 @@ public final class FixedWidthFontRenderer
|
|||||||
return 15 - Terminal.getColour( c, def );
|
return 15 - Terminal.getColour( c, def );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void drawChar( Matrix4f transform, VertexConsumer buffer, float x, float y, int index, float r, float g, float b, int light )
|
private static void drawChar( VertexEmitter emitter, float x, float y, int index, byte[] colour, int light )
|
||||||
{
|
{
|
||||||
// Short circuit to avoid the common case - the texture should be blank here after all.
|
// Short circuit to avoid the common case - the texture should be blank here after all.
|
||||||
if( index == '\0' || index == ' ' ) return;
|
if( index == '\0' || index == ' ' ) return;
|
||||||
@ -74,56 +81,40 @@ public final class FixedWidthFontRenderer
|
|||||||
int xStart = 1 + column * (FONT_WIDTH + 2);
|
int xStart = 1 + column * (FONT_WIDTH + 2);
|
||||||
int yStart = 1 + row * (FONT_HEIGHT + 2);
|
int yStart = 1 + row * (FONT_HEIGHT + 2);
|
||||||
|
|
||||||
buffer.vertex( transform, x, y, 0f ).color( r, g, b, 1.0f ).uv( xStart / WIDTH, yStart / WIDTH ).uv2( light ).endVertex();
|
emitter.vertex( x, y, (float) 0, colour, xStart / WIDTH, yStart / WIDTH, light );
|
||||||
buffer.vertex( transform, x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).uv( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).uv2( light ).endVertex();
|
emitter.vertex( x, y + FONT_HEIGHT, (float) 0, colour, xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH, light );
|
||||||
buffer.vertex( transform, x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).uv( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).uv2( light ).endVertex();
|
emitter.vertex( x + FONT_WIDTH, y + FONT_HEIGHT, (float) 0, colour, (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH, light );
|
||||||
buffer.vertex( transform, x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).uv( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).uv2( light ).endVertex();
|
emitter.vertex( x + FONT_WIDTH, y, (float) 0, colour, (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH, light );
|
||||||
buffer.vertex( transform, x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).uv( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).uv2( light ).endVertex();
|
|
||||||
buffer.vertex( transform, x + FONT_WIDTH, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).uv( (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).uv2( light ).endVertex();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void drawQuad( Matrix4f transform, VertexConsumer buffer, float x, float y, float width, float height, float r, float g, float b )
|
public static void drawQuad( VertexEmitter emitter, float x, float y, float z, float width, float height, byte[] colour, int light )
|
||||||
{
|
{
|
||||||
buffer.vertex( transform, x, y, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_START, BACKGROUND_START ).endVertex();
|
emitter.vertex( x, y, z, colour, BACKGROUND_START, BACKGROUND_START, light );
|
||||||
buffer.vertex( transform, x, y + height, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_START, BACKGROUND_END ).endVertex();
|
emitter.vertex( x, y + height, z, colour, BACKGROUND_START, BACKGROUND_END, light );
|
||||||
buffer.vertex( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_START ).endVertex();
|
emitter.vertex( x + width, y + height, z, colour, BACKGROUND_END, BACKGROUND_END, light );
|
||||||
buffer.vertex( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_START ).endVertex();
|
emitter.vertex( x + width, y, z, colour, BACKGROUND_END, BACKGROUND_START, light );
|
||||||
buffer.vertex( transform, x, y + height, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_START, BACKGROUND_END ).endVertex();
|
|
||||||
buffer.vertex( transform, x + width, y + height, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_END ).endVertex();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void drawQuad( Matrix4f transform, VertexConsumer buffer, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex )
|
private static void drawQuad( VertexEmitter emitter, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex, int light )
|
||||||
{
|
{
|
||||||
double[] colour = palette.getColour( getColour( colourIndex, Colour.BLACK ) );
|
var colour = palette.getByteColour( getColour( colourIndex, Colour.BLACK ), greyscale );
|
||||||
float r, g, b;
|
drawQuad( emitter, x, y, 0, width, height, colour, light );
|
||||||
if( greyscale )
|
|
||||||
{
|
|
||||||
r = g = b = toGreyscale( colour );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r = (float) colour[0];
|
|
||||||
g = (float) colour[1];
|
|
||||||
b = (float) colour[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
drawQuad( transform, buffer, x, y, width, height, r, g, b );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void drawBackground(
|
private static void drawBackground(
|
||||||
@Nonnull Matrix4f transform, @Nonnull VertexConsumer renderer, float x, float y,
|
@Nonnull VertexEmitter emitter, float x, float y,
|
||||||
@Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale,
|
@Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale,
|
||||||
float leftMarginSize, float rightMarginSize, float height
|
float leftMarginSize, float rightMarginSize, float height, int light
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if( leftMarginSize > 0 )
|
if( leftMarginSize > 0 )
|
||||||
{
|
{
|
||||||
drawQuad( transform, renderer, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ) );
|
drawQuad( emitter, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ), light );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( rightMarginSize > 0 )
|
if( rightMarginSize > 0 )
|
||||||
{
|
{
|
||||||
drawQuad( transform, renderer, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, greyscale, backgroundColour.charAt( backgroundColour.length() - 1 ) );
|
drawQuad( emitter, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, greyscale, backgroundColour.charAt( backgroundColour.length() - 1 ), light );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Batch together runs of identical background cells.
|
// Batch together runs of identical background cells.
|
||||||
@ -136,7 +127,7 @@ public final class FixedWidthFontRenderer
|
|||||||
|
|
||||||
if( blockColour != '\0' )
|
if( blockColour != '\0' )
|
||||||
{
|
{
|
||||||
drawQuad( transform, renderer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour );
|
drawQuad( emitter, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour, light );
|
||||||
}
|
}
|
||||||
|
|
||||||
blockColour = colourIndex;
|
blockColour = colourIndex;
|
||||||
@ -145,46 +136,35 @@ public final class FixedWidthFontRenderer
|
|||||||
|
|
||||||
if( blockColour != '\0' )
|
if( blockColour != '\0' )
|
||||||
{
|
{
|
||||||
drawQuad( transform, renderer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, greyscale, blockColour );
|
drawQuad( emitter, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, greyscale, blockColour, light );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void drawString(
|
public static void drawString(
|
||||||
@Nonnull Matrix4f transform, @Nonnull VertexConsumer renderer, float x, float y,
|
@Nonnull VertexEmitter emitter, float x, float y,
|
||||||
@Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour,
|
@Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour,
|
||||||
@Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize, int light
|
@Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize, int light
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if( backgroundColour != null )
|
if( backgroundColour != null )
|
||||||
{
|
{
|
||||||
drawBackground( transform, renderer, x, y, backgroundColour, palette, greyscale, leftMarginSize, rightMarginSize, FONT_HEIGHT );
|
drawBackground( emitter, x, y, backgroundColour, palette, greyscale, leftMarginSize, rightMarginSize, FONT_HEIGHT, light );
|
||||||
}
|
}
|
||||||
|
|
||||||
for( int i = 0; i < text.length(); i++ )
|
for( int i = 0; i < text.length(); i++ )
|
||||||
{
|
{
|
||||||
double[] colour = palette.getColour( getColour( textColour.charAt( i ), Colour.BLACK ) );
|
var colour = palette.getByteColour( getColour( textColour.charAt( i ), Colour.BLACK ), greyscale );
|
||||||
float r, g, b;
|
|
||||||
if( greyscale )
|
|
||||||
{
|
|
||||||
r = g = b = toGreyscale( colour );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r = (float) colour[0];
|
|
||||||
g = (float) colour[1];
|
|
||||||
b = (float) colour[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw char
|
// Draw char
|
||||||
int index = text.charAt( i );
|
int index = text.charAt( i );
|
||||||
if( index > 255 ) index = '?';
|
if( index > 255 ) index = '?';
|
||||||
drawChar( transform, renderer, x + i * FONT_WIDTH, y, index, r, g, b, light );
|
drawChar( emitter, x + i * FONT_WIDTH, y, index, colour, light );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void drawTerminalWithoutCursor(
|
public static void drawTerminalWithoutCursor(
|
||||||
@Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y,
|
@Nonnull VertexEmitter emitter, float x, float y,
|
||||||
@Nonnull Terminal terminal, boolean greyscale,
|
@Nonnull Terminal terminal, boolean greyscale,
|
||||||
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
|
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
|
||||||
)
|
)
|
||||||
@ -194,32 +174,29 @@ public final class FixedWidthFontRenderer
|
|||||||
|
|
||||||
// Top and bottom margins
|
// Top and bottom margins
|
||||||
drawBackground(
|
drawBackground(
|
||||||
transform, buffer, x, y - topMarginSize,
|
emitter, x, y - topMarginSize,
|
||||||
terminal.getBackgroundColourLine( 0 ), palette, greyscale,
|
terminal.getBackgroundColourLine( 0 ), palette, greyscale,
|
||||||
leftMarginSize, rightMarginSize, topMarginSize
|
leftMarginSize, rightMarginSize, topMarginSize, FULL_BRIGHT_LIGHTMAP
|
||||||
);
|
);
|
||||||
|
|
||||||
drawBackground(
|
drawBackground(
|
||||||
transform, buffer, x, y + height * FONT_HEIGHT,
|
emitter, x, y + height * FONT_HEIGHT,
|
||||||
terminal.getBackgroundColourLine( height - 1 ), palette, greyscale,
|
terminal.getBackgroundColourLine( height - 1 ), palette, greyscale,
|
||||||
leftMarginSize, rightMarginSize, bottomMarginSize
|
leftMarginSize, rightMarginSize, bottomMarginSize, FULL_BRIGHT_LIGHTMAP
|
||||||
);
|
);
|
||||||
|
|
||||||
// The main text
|
// The main text
|
||||||
for( int i = 0; i < height; i++ )
|
for( int i = 0; i < height; i++ )
|
||||||
{
|
{
|
||||||
drawString(
|
drawString(
|
||||||
transform, buffer, x, y + FixedWidthFontRenderer.FONT_HEIGHT * i,
|
emitter, x, y + FixedWidthFontRenderer.FONT_HEIGHT * i,
|
||||||
terminal.getLine( i ), terminal.getTextColourLine( i ), terminal.getBackgroundColourLine( i ),
|
terminal.getLine( i ), terminal.getTextColourLine( i ), terminal.getBackgroundColourLine( i ),
|
||||||
palette, greyscale, leftMarginSize, rightMarginSize, FULL_BRIGHT_LIGHTMAP
|
palette, greyscale, leftMarginSize, rightMarginSize, FULL_BRIGHT_LIGHTMAP
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void drawCursor(
|
public static void drawCursor( @Nonnull VertexEmitter emitter, float x, float y, @Nonnull Terminal terminal, boolean greyscale )
|
||||||
@Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y,
|
|
||||||
@Nonnull Terminal terminal, boolean greyscale
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
Palette palette = terminal.getPalette();
|
Palette palette = terminal.getPalette();
|
||||||
int width = terminal.getWidth();
|
int width = terminal.getWidth();
|
||||||
@ -229,60 +206,100 @@ public final class FixedWidthFontRenderer
|
|||||||
int cursorY = terminal.getCursorY();
|
int cursorY = terminal.getCursorY();
|
||||||
if( terminal.getCursorBlink() && cursorX >= 0 && cursorX < width && cursorY >= 0 && cursorY < height && FrameInfo.getGlobalCursorBlink() )
|
if( terminal.getCursorBlink() && cursorX >= 0 && cursorX < width && cursorY >= 0 && cursorY < height && FrameInfo.getGlobalCursorBlink() )
|
||||||
{
|
{
|
||||||
double[] colour = palette.getColour( 15 - terminal.getTextColour() );
|
var colour = palette.getByteColour( 15 - terminal.getTextColour(), greyscale );
|
||||||
float r, g, b;
|
drawChar( emitter, x + cursorX * FONT_WIDTH, y + cursorY * FONT_HEIGHT, '_', colour, FULL_BRIGHT_LIGHTMAP );
|
||||||
if( greyscale )
|
|
||||||
{
|
|
||||||
r = g = b = toGreyscale( colour );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r = (float) colour[0];
|
|
||||||
g = (float) colour[1];
|
|
||||||
b = (float) colour[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
drawChar( transform, buffer, x + cursorX * FONT_WIDTH, y + cursorY * FONT_HEIGHT, '_', r, g, b, FULL_BRIGHT_LIGHTMAP );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void drawTerminal(
|
public static void drawTerminal(
|
||||||
@Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y,
|
@Nonnull VertexEmitter buffer, float x, float y,
|
||||||
@Nonnull Terminal terminal, boolean greyscale,
|
@Nonnull Terminal terminal, boolean greyscale,
|
||||||
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
|
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
drawTerminalWithoutCursor( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
|
drawTerminalWithoutCursor( buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
|
||||||
drawCursor( transform, buffer, x, y, terminal, greyscale );
|
drawCursor( buffer, x, y, terminal, greyscale );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void drawTerminal(
|
public static void drawEmptyTerminal( @Nonnull VertexEmitter emitter, float x, float y, float width, float height )
|
||||||
@Nonnull Matrix4f transform, float x, float y, @Nonnull Terminal terminal, boolean greyscale,
|
|
||||||
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
MultiBufferSource.BufferSource renderer = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() );
|
drawQuad( emitter, x, y, 0, width, height, BLACK, FULL_BRIGHT_LIGHTMAP );
|
||||||
VertexConsumer buffer = renderer.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH );
|
|
||||||
drawTerminal( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
|
|
||||||
renderer.endBatch();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void drawEmptyTerminal( @Nonnull Matrix4f transform, @Nonnull MultiBufferSource renderer, float x, float y, float width, float height )
|
public static void drawBlocker( @Nonnull VertexEmitter emitter, float x, float y, float width, float height )
|
||||||
{
|
{
|
||||||
Colour colour = Colour.BLACK;
|
drawQuad( emitter, x, y, 0, width, height, BLACK, FULL_BRIGHT_LIGHTMAP );
|
||||||
drawQuad( transform, renderer.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void drawEmptyTerminal( @Nonnull Matrix4f transform, float x, float y, float width, float height )
|
public static int getVertexCount( Terminal terminal )
|
||||||
{
|
{
|
||||||
MultiBufferSource.BufferSource renderer = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() );
|
int height = terminal.getHeight();
|
||||||
drawEmptyTerminal( transform, renderer, x, y, width, height );
|
int count = 0;
|
||||||
renderer.endBatch();
|
|
||||||
|
for( int y = 0; y < height; y++ )
|
||||||
|
{
|
||||||
|
// We compress runs of adjacent characters, so we need to do that calculation here too :/.
|
||||||
|
int background = 2;
|
||||||
|
TextBuffer backgroundColour = terminal.getBackgroundColourLine( y );
|
||||||
|
char blockColour = '\0';
|
||||||
|
for( int x = 0; x < backgroundColour.length(); x++ )
|
||||||
|
{
|
||||||
|
char colourIndex = backgroundColour.charAt( x );
|
||||||
|
if( colourIndex == blockColour ) continue;
|
||||||
|
|
||||||
|
if( blockColour != '\0' ) background++;
|
||||||
|
blockColour = colourIndex;
|
||||||
|
}
|
||||||
|
if( blockColour != '\0' ) background++;
|
||||||
|
|
||||||
|
count += background;
|
||||||
|
if( y == 0 ) count += background;
|
||||||
|
if( y == height - 1 ) count += background;
|
||||||
|
|
||||||
|
// Thankfully the normal characters are much easier!
|
||||||
|
TextBuffer foreground = terminal.getLine( y );
|
||||||
|
for( int x = 0; x < foreground.length(); x++ )
|
||||||
|
{
|
||||||
|
char c = foreground.charAt( x );
|
||||||
|
if( c != '\0' && c != ' ' ) count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void drawBlocker( @Nonnull Matrix4f transform, @Nonnull MultiBufferSource renderer, float x, float y, float width, float height )
|
/**
|
||||||
|
* Emit a single vertex to some buffer.
|
||||||
|
*
|
||||||
|
* @see #toVertexConsumer(Matrix4f, VertexConsumer) Emits to a {@link VertexConsumer}.
|
||||||
|
* @see #toByteBuffer(ByteBuffer) Emits to a {@link ByteBuffer}.
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface VertexEmitter
|
||||||
{
|
{
|
||||||
Colour colour = Colour.BLACK;
|
void vertex( float x, float y, float z, byte[] rgba, float u, float v, int light );
|
||||||
drawQuad( transform, renderer.getBuffer( RenderTypes.TERMINAL_BLOCKER ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() );
|
}
|
||||||
|
|
||||||
|
public static VertexEmitter toVertexConsumer( Matrix4f matrix, VertexConsumer consumer )
|
||||||
|
{
|
||||||
|
return ( float x, float y, float z, byte[] rgba, float u, float v, int light ) ->
|
||||||
|
consumer.vertex( matrix, x, y, z ).color( rgba[0], rgba[1], rgba[2], rgba[3] ).uv( u, v ).uv2( light ).endVertex();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optimised vertex emitter which bypasses {@link VertexConsumer}. This allows us to emit vertices very quickly,
|
||||||
|
* when using the VBO renderer with some limitations:
|
||||||
|
* <ul>
|
||||||
|
* <li>No transformation matrix (not needed for VBOs).</li>
|
||||||
|
* <li>Only works with {@link DefaultVertexFormat#POSITION_COLOR_TEX_LIGHTMAP}.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param buffer The buffer to emit to. This must have space for at least {@link #getVertexCount(Terminal)} vertices.
|
||||||
|
* @return The emitter, ot be passed to the rendering functions.
|
||||||
|
*/
|
||||||
|
public static VertexEmitter toByteBuffer( ByteBuffer buffer )
|
||||||
|
{
|
||||||
|
return ( float x, float y, float z, byte[] rgba, float u, float v, int light ) -> buffer
|
||||||
|
.putFloat( x ).putFloat( y ).putFloat( z ).put( rgba ).putFloat( u ).putFloat( v );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,14 +6,17 @@
|
|||||||
package dan200.computercraft.client.gui.widgets;
|
package dan200.computercraft.client.gui.widgets;
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.blaze3d.vertex.Tesselator;
|
||||||
import com.mojang.math.Matrix4f;
|
import com.mojang.math.Matrix4f;
|
||||||
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
|
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
|
||||||
|
import dan200.computercraft.client.render.RenderTypes;
|
||||||
import dan200.computercraft.core.terminal.Terminal;
|
import dan200.computercraft.core.terminal.Terminal;
|
||||||
import dan200.computercraft.shared.computer.core.ClientComputer;
|
import dan200.computercraft.shared.computer.core.ClientComputer;
|
||||||
import net.minecraft.SharedConstants;
|
import net.minecraft.SharedConstants;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.components.AbstractWidget;
|
import net.minecraft.client.gui.components.AbstractWidget;
|
||||||
import net.minecraft.client.gui.narration.NarrationElementOutput;
|
import net.minecraft.client.gui.narration.NarrationElementOutput;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
import net.minecraft.network.chat.TextComponent;
|
import net.minecraft.network.chat.TextComponent;
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
@ -315,14 +318,24 @@ public class WidgetTerminal extends AbstractWidget
|
|||||||
if( !visible ) return;
|
if( !visible ) return;
|
||||||
Matrix4f matrix = transform.last().pose();
|
Matrix4f matrix = transform.last().pose();
|
||||||
Terminal terminal = computer.getTerminal();
|
Terminal terminal = computer.getTerminal();
|
||||||
|
|
||||||
|
var bufferSource = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() );
|
||||||
|
var emitter = FixedWidthFontRenderer.toVertexConsumer( matrix, bufferSource.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH ) );
|
||||||
|
|
||||||
if( terminal != null )
|
if( terminal != null )
|
||||||
{
|
{
|
||||||
FixedWidthFontRenderer.drawTerminal( matrix, innerX, innerY, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN );
|
boolean greyscale = !computer.isColour();
|
||||||
|
FixedWidthFontRenderer.drawTerminal(
|
||||||
|
emitter,
|
||||||
|
(float) innerX, (float) innerY, terminal, greyscale, (float) MARGIN, (float) MARGIN, (float) MARGIN, (float) MARGIN
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FixedWidthFontRenderer.drawEmptyTerminal( matrix, x, y, width, height );
|
FixedWidthFontRenderer.drawEmptyTerminal( emitter, (float) x, (float) y, (float) width, (float) height );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bufferSource.endBatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -54,7 +54,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void renderItem( PoseStack transform, MultiBufferSource renderer, ItemStack stack, int light )
|
protected void renderItem( PoseStack transform, MultiBufferSource bufferSource, ItemStack stack, int light )
|
||||||
{
|
{
|
||||||
ClientComputer computer = ItemPocketComputer.createClientComputer( stack );
|
ClientComputer computer = ItemPocketComputer.createClientComputer( stack );
|
||||||
Terminal terminal = computer == null ? null : computer.getTerminal();
|
Terminal terminal = computer == null ? null : computer.getTerminal();
|
||||||
@ -91,24 +91,30 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
|
|||||||
int frameColour = item.getColour( stack );
|
int frameColour = item.getColour( stack );
|
||||||
|
|
||||||
Matrix4f matrix = transform.last().pose();
|
Matrix4f matrix = transform.last().pose();
|
||||||
renderFrame( matrix, renderer, family, frameColour, light, width, height );
|
renderFrame( matrix, bufferSource, family, frameColour, light, width, height );
|
||||||
|
|
||||||
// Render the light
|
// Render the light
|
||||||
int lightColour = ItemPocketComputer.getLightState( stack );
|
int lightColour = ItemPocketComputer.getLightState( stack );
|
||||||
if( lightColour == -1 ) lightColour = Colour.BLACK.getHex();
|
if( lightColour == -1 ) lightColour = Colour.BLACK.getHex();
|
||||||
renderLight( matrix, renderer, lightColour, width, height );
|
renderLight( matrix, bufferSource, lightColour, width, height );
|
||||||
|
|
||||||
if( computer != null && terminal != null )
|
if( computer != null && terminal != null )
|
||||||
{
|
{
|
||||||
FixedWidthFontRenderer.drawTerminal(
|
FixedWidthFontRenderer.drawTerminal(
|
||||||
matrix, renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ),
|
FixedWidthFontRenderer.toVertexConsumer( matrix, bufferSource.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ) ),
|
||||||
MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN
|
MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN
|
||||||
);
|
);
|
||||||
FixedWidthFontRenderer.drawBlocker( transform.last().pose(), renderer, 0, 0, width, height );
|
FixedWidthFontRenderer.drawBlocker(
|
||||||
|
FixedWidthFontRenderer.toVertexConsumer( matrix, bufferSource.getBuffer( RenderTypes.TERMINAL_BLOCKER ) ),
|
||||||
|
0, 0, width, height
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FixedWidthFontRenderer.drawEmptyTerminal( matrix, renderer, 0, 0, width, height );
|
FixedWidthFontRenderer.drawEmptyTerminal(
|
||||||
|
FixedWidthFontRenderer.toVertexConsumer( matrix, bufferSource.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH ) ),
|
||||||
|
0, 0, width, height
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
transform.popPose();
|
transform.popPose();
|
||||||
@ -127,15 +133,16 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
|
|||||||
|
|
||||||
private static void renderLight( Matrix4f transform, MultiBufferSource render, int colour, int width, int height )
|
private static void renderLight( Matrix4f transform, MultiBufferSource render, int colour, int width, int height )
|
||||||
{
|
{
|
||||||
float r = ((colour >>> 16) & 0xFF) / 255.0f;
|
byte r = (byte) ((colour >>> 16) & 0xFF);
|
||||||
float g = ((colour >>> 8) & 0xFF) / 255.0f;
|
byte g = (byte) ((colour >>> 8) & 0xFF);
|
||||||
float b = (colour & 0xFF) / 255.0f;
|
byte b = (byte) (colour & 0xFF);
|
||||||
float z = 0.001f;
|
var c = new byte[] { r, g, b, (byte) 255 };
|
||||||
|
|
||||||
VertexConsumer buffer = render.getBuffer( RenderTypes.POSITION_COLOR );
|
VertexConsumer buffer = render.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH );
|
||||||
buffer.vertex( transform, width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).endVertex();
|
FixedWidthFontRenderer.drawQuad(
|
||||||
buffer.vertex( transform, width, height + LIGHT_HEIGHT + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).endVertex();
|
FixedWidthFontRenderer.toVertexConsumer( transform, buffer ),
|
||||||
buffer.vertex( transform, width, height + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).endVertex();
|
width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, 0.001f, LIGHT_HEIGHT * 2, LIGHT_HEIGHT,
|
||||||
buffer.vertex( transform, width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).endVertex();
|
c, RenderTypes.FULL_BRIGHT_LIGHTMAP
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,12 +54,13 @@ public final class PrintoutRenderer
|
|||||||
|
|
||||||
private PrintoutRenderer() {}
|
private PrintoutRenderer() {}
|
||||||
|
|
||||||
public static void drawText( Matrix4f transform, MultiBufferSource renderer, int x, int y, int start, int light, TextBuffer[] text, TextBuffer[] colours )
|
public static void drawText( Matrix4f transform, MultiBufferSource bufferSource, int x, int y, int start, int light, TextBuffer[] text, TextBuffer[] colours )
|
||||||
{
|
{
|
||||||
VertexConsumer buffer = renderer.getBuffer( RenderTypes.PRINTOUT_TEXT );
|
var buffer = bufferSource.getBuffer( RenderTypes.PRINTOUT_TEXT );
|
||||||
|
var emitter = FixedWidthFontRenderer.toVertexConsumer( transform, buffer );
|
||||||
for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ )
|
for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ )
|
||||||
{
|
{
|
||||||
FixedWidthFontRenderer.drawString( transform, buffer,
|
FixedWidthFontRenderer.drawString( emitter,
|
||||||
x, y + line * FONT_HEIGHT, text[start + line], colours[start + line], null, Palette.DEFAULT,
|
x, y + line * FONT_HEIGHT, text[start + line], colours[start + line], null, Palette.DEFAULT,
|
||||||
false, 0, 0,
|
false, 0, 0,
|
||||||
light
|
light
|
||||||
@ -67,12 +68,13 @@ public final class PrintoutRenderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void drawText( Matrix4f transform, MultiBufferSource renderer, int x, int y, int start, int light, String[] text, String[] colours )
|
public static void drawText( Matrix4f transform, MultiBufferSource bufferSource, int x, int y, int start, int light, String[] text, String[] colours )
|
||||||
{
|
{
|
||||||
VertexConsumer buffer = renderer.getBuffer( RenderTypes.PRINTOUT_TEXT );
|
var buffer = bufferSource.getBuffer( RenderTypes.PRINTOUT_TEXT );
|
||||||
|
var emitter = FixedWidthFontRenderer.toVertexConsumer( transform, buffer );
|
||||||
for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ )
|
for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ )
|
||||||
{
|
{
|
||||||
FixedWidthFontRenderer.drawString( transform, buffer,
|
FixedWidthFontRenderer.drawString( emitter,
|
||||||
x, y + line * FONT_HEIGHT,
|
x, y + line * FONT_HEIGHT,
|
||||||
new TextBuffer( text[start + line] ), new TextBuffer( colours[start + line] ),
|
new TextBuffer( text[start + line] ), new TextBuffer( colours[start + line] ),
|
||||||
null, Palette.DEFAULT, false, 0, 0,
|
null, Palette.DEFAULT, false, 0, 0,
|
||||||
@ -81,12 +83,12 @@ public final class PrintoutRenderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void drawBorder( Matrix4f transform, MultiBufferSource renderer, float x, float y, float z, int page, int pages, boolean isBook, int light )
|
public static void drawBorder( Matrix4f transform, MultiBufferSource bufferSource, float x, float y, float z, int page, int pages, boolean isBook, int light )
|
||||||
{
|
{
|
||||||
int leftPages = page;
|
int leftPages = page;
|
||||||
int rightPages = pages - page - 1;
|
int rightPages = pages - page - 1;
|
||||||
|
|
||||||
VertexConsumer buffer = renderer.getBuffer( RenderTypes.PRINTOUT_BACKGROUND );
|
VertexConsumer buffer = bufferSource.getBuffer( RenderTypes.PRINTOUT_BACKGROUND );
|
||||||
|
|
||||||
if( isBook )
|
if( isBook )
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,7 @@ import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
|||||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
|
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
|
||||||
|
import net.minecraft.client.renderer.GameRenderer;
|
||||||
import net.minecraft.client.renderer.RenderStateShard;
|
import net.minecraft.client.renderer.RenderStateShard;
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.client.renderer.ShaderInstance;
|
import net.minecraft.client.renderer.ShaderInstance;
|
||||||
@ -27,24 +28,45 @@ public class RenderTypes
|
|||||||
public static final int FULL_BRIGHT_LIGHTMAP = (0xF << 4) | (0xF << 20);
|
public static final int FULL_BRIGHT_LIGHTMAP = (0xF << 4) | (0xF << 20);
|
||||||
|
|
||||||
private static MonitorTextureBufferShader monitorTboShader;
|
private static MonitorTextureBufferShader monitorTboShader;
|
||||||
private static ShaderInstance terminalShader;
|
|
||||||
|
|
||||||
public static final RenderType TERMINAL_WITHOUT_DEPTH = Types.TERMINAL_WITHOUT_DEPTH;
|
|
||||||
public static final RenderType TERMINAL_BLOCKER = Types.TERMINAL_BLOCKER;
|
|
||||||
public static final RenderType TERMINAL_WITH_DEPTH = Types.TERMINAL_WITH_DEPTH;
|
|
||||||
public static final RenderType MONITOR_TBO = Types.MONITOR_TBO;
|
|
||||||
public static final RenderType PRINTOUT_TEXT = Types.PRINTOUT_TEXT;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This looks wrong (it should be POSITION_COLOR_TEX_LIGHTMAP surely!) but the fragment/vertex shader for that
|
* Renders a fullbright terminal without writing to the depth layer. This is used in combination with
|
||||||
* appear to entirely ignore the lightmap.
|
* {@link #TERMINAL_BLOCKER} to ensure we can render a terminal without z-fighting.
|
||||||
|
*/
|
||||||
|
public static final RenderType TERMINAL_WITHOUT_DEPTH = Types.TERMINAL_WITHOUT_DEPTH;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A transparent texture which only writes to the depth layer.
|
||||||
|
*/
|
||||||
|
public static final RenderType TERMINAL_BLOCKER = Types.TERMINAL_BLOCKER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a fullbright terminal which also writes to the depth layer. This is used when z-fighting isn't an issue -
|
||||||
|
* for instance rendering an empty terminal or inside a GUI.
|
||||||
*
|
*
|
||||||
* Note that vanilla maps do the same, so this isn't unreasonable.
|
* This is identical to <em>vanilla's</em> {@link RenderType#text}. Forge overrides one with a definition which sets
|
||||||
|
* sortOnUpload to true, which is entirely broken!
|
||||||
|
*/
|
||||||
|
public static final RenderType TERMINAL_WITH_DEPTH = Types.TERMINAL_WITH_DEPTH;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a monitor with the TBO shader.
|
||||||
|
*
|
||||||
|
* @see MonitorTextureBufferShader
|
||||||
|
*/
|
||||||
|
public static final RenderType MONITOR_TBO = Types.MONITOR_TBO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A variant of {@link #TERMINAL_WITH_DEPTH} which uses the lightmap rather than rendering fullbright.
|
||||||
|
*/
|
||||||
|
public static final RenderType PRINTOUT_TEXT = RenderType.text( FixedWidthFontRenderer.FONT );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Printout's background texture. {@link RenderType#text(ResourceLocation)} is a <em>little</em> questionable, but
|
||||||
|
* it is what maps use, so should behave the same as vanilla in both item frames and in-hand.
|
||||||
*/
|
*/
|
||||||
public static final RenderType PRINTOUT_BACKGROUND = RenderType.text( new ResourceLocation( "computercraft", "textures/gui/printout.png" ) );
|
public static final RenderType PRINTOUT_BACKGROUND = RenderType.text( new ResourceLocation( "computercraft", "textures/gui/printout.png" ) );
|
||||||
|
|
||||||
public static final RenderType POSITION_COLOR = Types.POSITION_COLOR;
|
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
static MonitorTextureBufferShader getMonitorTextureBufferShader()
|
static MonitorTextureBufferShader getMonitorTextureBufferShader()
|
||||||
{
|
{
|
||||||
@ -55,8 +77,7 @@ public class RenderTypes
|
|||||||
@Nonnull
|
@Nonnull
|
||||||
static ShaderInstance getTerminalShader()
|
static ShaderInstance getTerminalShader()
|
||||||
{
|
{
|
||||||
if( terminalShader == null ) throw new NullPointerException( "MonitorTboShader has not been registered" );
|
return GameRenderer.getPositionColorTexShader();
|
||||||
return terminalShader;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
@ -70,15 +91,6 @@ public class RenderTypes
|
|||||||
),
|
),
|
||||||
x -> monitorTboShader = (MonitorTextureBufferShader) x
|
x -> monitorTboShader = (MonitorTextureBufferShader) x
|
||||||
);
|
);
|
||||||
|
|
||||||
event.registerShader(
|
|
||||||
new ShaderInstance(
|
|
||||||
event.getResourceManager(),
|
|
||||||
new ResourceLocation( ComputerCraft.MOD_ID, "terminal" ),
|
|
||||||
TERMINAL_WITHOUT_DEPTH.format()
|
|
||||||
),
|
|
||||||
x -> terminalShader = x
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class Types extends RenderStateShard
|
private static final class Types extends RenderStateShard
|
||||||
@ -88,7 +100,6 @@ public class RenderTypes
|
|||||||
false, false // blur, minimap
|
false, false // blur, minimap
|
||||||
);
|
);
|
||||||
private static final VertexFormat TERM_FORMAT = DefaultVertexFormat.POSITION_COLOR_TEX;
|
private static final VertexFormat TERM_FORMAT = DefaultVertexFormat.POSITION_COLOR_TEX;
|
||||||
private static final VertexFormat.Mode TERM_MODE = VertexFormat.Mode.TRIANGLES;
|
|
||||||
private static final ShaderStateShard TERM_SHADER = new ShaderStateShard( RenderTypes::getTerminalShader );
|
private static final ShaderStateShard TERM_SHADER = new ShaderStateShard( RenderTypes::getTerminalShader );
|
||||||
|
|
||||||
static final RenderType MONITOR_TBO = RenderType.create(
|
static final RenderType MONITOR_TBO = RenderType.create(
|
||||||
@ -102,52 +113,32 @@ public class RenderTypes
|
|||||||
);
|
);
|
||||||
|
|
||||||
static final RenderType TERMINAL_WITHOUT_DEPTH = RenderType.create(
|
static final RenderType TERMINAL_WITHOUT_DEPTH = RenderType.create(
|
||||||
"terminal_without_depth", TERM_FORMAT, TERM_MODE, 1024,
|
"terminal_without_depth", TERM_FORMAT, VertexFormat.Mode.QUADS, 1024,
|
||||||
false, false, // useDelegate, needsSorting
|
false, false, // useDelegate, needsSorting
|
||||||
RenderType.CompositeState.builder()
|
RenderType.CompositeState.builder()
|
||||||
.setTextureState( TERM_FONT_TEXTURE )
|
.setTextureState( TERM_FONT_TEXTURE )
|
||||||
.setShaderState( TERM_SHADER )
|
.setShaderState( TERM_SHADER )
|
||||||
|
.setLightmapState( LIGHTMAP )
|
||||||
.setWriteMaskState( COLOR_WRITE )
|
.setWriteMaskState( COLOR_WRITE )
|
||||||
.createCompositeState( false )
|
.createCompositeState( false )
|
||||||
);
|
);
|
||||||
|
|
||||||
static final RenderType TERMINAL_BLOCKER = RenderType.create(
|
static final RenderType TERMINAL_BLOCKER = RenderType.create(
|
||||||
"terminal_blocker", TERM_FORMAT, TERM_MODE, 256,
|
"terminal_blocker", DefaultVertexFormat.POSITION, VertexFormat.Mode.QUADS, 256,
|
||||||
false, false, // useDelegate, needsSorting
|
false, false, // useDelegate, needsSorting
|
||||||
RenderType.CompositeState.builder()
|
RenderType.CompositeState.builder()
|
||||||
.setTextureState( TERM_FONT_TEXTURE )
|
.setShaderState( POSITION_SHADER )
|
||||||
.setShaderState( TERM_SHADER )
|
|
||||||
.setWriteMaskState( DEPTH_WRITE )
|
.setWriteMaskState( DEPTH_WRITE )
|
||||||
.createCompositeState( false )
|
.createCompositeState( false )
|
||||||
);
|
);
|
||||||
|
|
||||||
static final RenderType TERMINAL_WITH_DEPTH = RenderType.create(
|
static final RenderType TERMINAL_WITH_DEPTH = RenderType.create(
|
||||||
"terminal_with_depth", TERM_FORMAT, TERM_MODE, 1024,
|
"terminal_with_depth", TERM_FORMAT, VertexFormat.Mode.QUADS, 1024,
|
||||||
false, false, // useDelegate, needsSorting
|
false, false, // useDelegate, needsSorting
|
||||||
RenderType.CompositeState.builder()
|
RenderType.CompositeState.builder()
|
||||||
.setTextureState( TERM_FONT_TEXTURE )
|
.setTextureState( TERM_FONT_TEXTURE )
|
||||||
.setShaderState( TERM_SHADER )
|
.setShaderState( TERM_SHADER )
|
||||||
.createCompositeState( false )
|
.setLightmapState( LIGHTMAP )
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A variant of {@link #TERMINAL_WITH_DEPTH} which uses the lightmap rather than rendering fullbright.
|
|
||||||
*/
|
|
||||||
static final RenderType PRINTOUT_TEXT = RenderType.create(
|
|
||||||
"printout_text", DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP, TERM_MODE, 1024,
|
|
||||||
false, false, // useDelegate, needsSorting
|
|
||||||
RenderType.CompositeState.builder()
|
|
||||||
.setTextureState( TERM_FONT_TEXTURE )
|
|
||||||
.setShaderState( RenderStateShard.RENDERTYPE_TEXT_SHADER )
|
|
||||||
.setLightmapState( RenderStateShard.LIGHTMAP )
|
|
||||||
.createCompositeState( false )
|
|
||||||
);
|
|
||||||
|
|
||||||
static final RenderType POSITION_COLOR = RenderType.create(
|
|
||||||
"position_color", DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.QUADS, 128,
|
|
||||||
false, false, // useDelegate, needsSorting
|
|
||||||
RenderType.CompositeState.builder()
|
|
||||||
.setShaderState( POSITION_COLOR_SHADER )
|
|
||||||
.createCompositeState( false )
|
.createCompositeState( false )
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -8,9 +8,9 @@ package dan200.computercraft.client.render;
|
|||||||
import com.mojang.blaze3d.platform.GlStateManager;
|
import com.mojang.blaze3d.platform.GlStateManager;
|
||||||
import com.mojang.blaze3d.platform.MemoryTracker;
|
import com.mojang.blaze3d.platform.MemoryTracker;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
import com.mojang.blaze3d.vertex.*;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
import com.mojang.math.Matrix4f;
|
import com.mojang.math.Matrix4f;
|
||||||
import com.mojang.math.Transformation;
|
|
||||||
import com.mojang.math.Vector3f;
|
import com.mojang.math.Vector3f;
|
||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
import dan200.computercraft.client.FrameInfo;
|
import dan200.computercraft.client.FrameInfo;
|
||||||
@ -44,16 +44,14 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonito
|
|||||||
* the monitor frame and contents.
|
* the monitor frame and contents.
|
||||||
*/
|
*/
|
||||||
private static final float MARGIN = (float) (TileMonitor.RENDER_MARGIN * 1.1);
|
private static final float MARGIN = (float) (TileMonitor.RENDER_MARGIN * 1.1);
|
||||||
private static ByteBuffer tboContents;
|
private static ByteBuffer backingBuffer;
|
||||||
|
|
||||||
private static final Matrix4f IDENTITY = Transformation.identity().getMatrix();
|
|
||||||
|
|
||||||
public TileEntityMonitorRenderer( BlockEntityRendererProvider.Context context )
|
public TileEntityMonitorRenderer( BlockEntityRendererProvider.Context context )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render( @Nonnull TileMonitor monitor, float partialTicks, @Nonnull PoseStack transform, @Nonnull MultiBufferSource renderer, int lightmapCoord, int overlayLight )
|
public void render( @Nonnull TileMonitor monitor, float partialTicks, @Nonnull PoseStack transform, @Nonnull MultiBufferSource bufferSource, int lightmapCoord, int overlayLight )
|
||||||
{
|
{
|
||||||
// Render from the origin monitor
|
// Render from the origin monitor
|
||||||
ClientMonitor originTerminal = monitor.getClientMonitor();
|
ClientMonitor originTerminal = monitor.getClientMonitor();
|
||||||
@ -114,31 +112,31 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonito
|
|||||||
|
|
||||||
Matrix4f matrix = transform.last().pose();
|
Matrix4f matrix = transform.last().pose();
|
||||||
|
|
||||||
renderTerminal( renderer, matrix, originTerminal, (float) (MARGIN / xScale), (float) (MARGIN / yScale) );
|
renderTerminal( bufferSource, matrix, originTerminal, (float) (MARGIN / xScale), (float) (MARGIN / yScale) );
|
||||||
|
|
||||||
// We don't draw the cursor with the VBO, as it's dynamic and so we'll end up refreshing far more than is
|
// We don't draw the cursor with the VBO/TBO, as it's dynamic and so we'll end up refreshing far more than
|
||||||
// reasonable.
|
// is reasonable.
|
||||||
FixedWidthFontRenderer.drawCursor(
|
FixedWidthFontRenderer.drawCursor(
|
||||||
matrix, renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ),
|
FixedWidthFontRenderer.toVertexConsumer( matrix, bufferSource.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ) ),
|
||||||
0, 0, terminal, !originTerminal.isColour()
|
0, 0, terminal, !originTerminal.isColour()
|
||||||
);
|
);
|
||||||
|
|
||||||
transform.popPose();
|
transform.popPose();
|
||||||
|
|
||||||
FixedWidthFontRenderer.drawBlocker(
|
FixedWidthFontRenderer.drawBlocker(
|
||||||
transform.last().pose(), renderer,
|
FixedWidthFontRenderer.toVertexConsumer( transform.last().pose(), bufferSource.getBuffer( RenderTypes.TERMINAL_BLOCKER ) ),
|
||||||
-MARGIN, MARGIN,
|
-MARGIN, MARGIN,
|
||||||
(float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)
|
(float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Force a flush of the blocker. WorldRenderer.updateCameraAndRender will "finish" all the built-in
|
// Force a flush of the blocker. WorldRenderer.updateCameraAndRender will "finish" all the built-in
|
||||||
// buffers before calling renderer.finish, which means the blocker isn't actually rendered at that point!
|
// buffers before calling renderer.finish, which means the blocker isn't actually rendered at that point!
|
||||||
renderer.getBuffer( RenderType.solid() );
|
bufferSource.getBuffer( RenderType.solid() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FixedWidthFontRenderer.drawEmptyTerminal(
|
FixedWidthFontRenderer.drawEmptyTerminal(
|
||||||
transform.last().pose(), renderer,
|
FixedWidthFontRenderer.toVertexConsumer( transform.last().pose(), bufferSource.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH ) ),
|
||||||
-MARGIN, MARGIN,
|
-MARGIN, MARGIN,
|
||||||
(float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)
|
(float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)
|
||||||
);
|
);
|
||||||
@ -147,7 +145,7 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonito
|
|||||||
transform.popPose();
|
transform.popPose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void renderTerminal( @Nonnull MultiBufferSource renderer, Matrix4f matrix, ClientMonitor monitor, float xMargin, float yMargin )
|
private static void renderTerminal( @Nonnull MultiBufferSource bufferSource, Matrix4f matrix, ClientMonitor monitor, float xMargin, float yMargin )
|
||||||
{
|
{
|
||||||
Terminal terminal = monitor.getTerminal();
|
Terminal terminal = monitor.getTerminal();
|
||||||
|
|
||||||
@ -164,14 +162,7 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonito
|
|||||||
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
|
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
|
||||||
if( redraw )
|
if( redraw )
|
||||||
{
|
{
|
||||||
int size = width * height * 3;
|
ByteBuffer monitorBuffer = getBuffer( width * height * 3 );
|
||||||
if( tboContents == null || tboContents.capacity() < size )
|
|
||||||
{
|
|
||||||
tboContents = MemoryTracker.create( size );
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer monitorBuffer = tboContents;
|
|
||||||
monitorBuffer.clear();
|
|
||||||
for( int y = 0; y < height; y++ )
|
for( int y = 0; y < height; y++ )
|
||||||
{
|
{
|
||||||
TextBuffer text = terminal.getLine( y ), textColour = terminal.getTextColourLine( y ), background = terminal.getBackgroundColourLine( y );
|
TextBuffer text = terminal.getLine( y ), textColour = terminal.getTextColourLine( y ), background = terminal.getBackgroundColourLine( y );
|
||||||
@ -198,7 +189,7 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonito
|
|||||||
MonitorTextureBufferShader shader = RenderTypes.getMonitorTextureBufferShader();
|
MonitorTextureBufferShader shader = RenderTypes.getMonitorTextureBufferShader();
|
||||||
shader.setupUniform( width, height, terminal.getPalette(), !monitor.isColour() );
|
shader.setupUniform( width, height, terminal.getPalette(), !monitor.isColour() );
|
||||||
|
|
||||||
VertexConsumer buffer = renderer.getBuffer( RenderTypes.MONITOR_TBO );
|
VertexConsumer buffer = bufferSource.getBuffer( RenderTypes.MONITOR_TBO );
|
||||||
tboVertex( buffer, matrix, -xMargin, -yMargin );
|
tboVertex( buffer, matrix, -xMargin, -yMargin );
|
||||||
tboVertex( buffer, matrix, -xMargin, pixelHeight + yMargin );
|
tboVertex( buffer, matrix, -xMargin, pixelHeight + yMargin );
|
||||||
tboVertex( buffer, matrix, pixelWidth + xMargin, -yMargin );
|
tboVertex( buffer, matrix, pixelWidth + xMargin, -yMargin );
|
||||||
@ -206,28 +197,27 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonito
|
|||||||
|
|
||||||
// And force things to flush. We strictly speaking do this later on anyway for the cursor, but nice to
|
// And force things to flush. We strictly speaking do this later on anyway for the cursor, but nice to
|
||||||
// be consistent.
|
// be consistent.
|
||||||
renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH );
|
bufferSource.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case VBO:
|
case VBO:
|
||||||
{
|
{
|
||||||
VertexBuffer vbo = monitor.buffer;
|
var vbo = monitor.buffer;
|
||||||
if( redraw )
|
if( redraw )
|
||||||
{
|
{
|
||||||
Tesselator tessellator = Tesselator.getInstance();
|
int vertexCount = FixedWidthFontRenderer.getVertexCount( terminal );
|
||||||
BufferBuilder builder = tessellator.getBuilder();
|
ByteBuffer buffer = getBuffer( vertexCount * RenderTypes.TERMINAL_WITHOUT_DEPTH.format().getVertexSize() );
|
||||||
builder.begin( RenderTypes.TERMINAL_WITHOUT_DEPTH.mode(), RenderTypes.TERMINAL_WITHOUT_DEPTH.format() );
|
|
||||||
FixedWidthFontRenderer.drawTerminalWithoutCursor(
|
FixedWidthFontRenderer.drawTerminalWithoutCursor(
|
||||||
IDENTITY, builder, 0, 0,
|
FixedWidthFontRenderer.toByteBuffer( buffer ), 0, 0,
|
||||||
terminal, !monitor.isColour(), yMargin, yMargin, xMargin, xMargin
|
terminal, !monitor.isColour(), yMargin, yMargin, xMargin, xMargin
|
||||||
);
|
);
|
||||||
|
buffer.flip();
|
||||||
|
|
||||||
builder.end();
|
vbo.upload( vertexCount, RenderTypes.TERMINAL_WITHOUT_DEPTH.mode(), RenderTypes.TERMINAL_WITHOUT_DEPTH.format(), buffer );
|
||||||
vbo.upload( builder );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH );
|
bufferSource.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH );
|
||||||
RenderTypes.TERMINAL_WITHOUT_DEPTH.setupRenderState();
|
RenderTypes.TERMINAL_WITHOUT_DEPTH.setupRenderState();
|
||||||
vbo.drawWithShader( matrix, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader() );
|
vbo.drawWithShader( matrix, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader() );
|
||||||
break;
|
break;
|
||||||
@ -241,6 +231,20 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonito
|
|||||||
builder.vertex( matrix, x, y, 0 ).uv( x, y ).endVertex();
|
builder.vertex( matrix, x, y, 0 ).uv( x, y ).endVertex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private static ByteBuffer getBuffer( int capacity )
|
||||||
|
{
|
||||||
|
|
||||||
|
ByteBuffer buffer = backingBuffer;
|
||||||
|
if( buffer == null || buffer.capacity() < capacity )
|
||||||
|
{
|
||||||
|
buffer = backingBuffer = MemoryTracker.create( capacity );
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.clear();
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getViewDistance()
|
public int getViewDistance()
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.BufferUploader;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexBuffer;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
import org.lwjgl.opengl.GL;
|
||||||
|
import org.lwjgl.opengl.GL15;
|
||||||
|
import org.lwjgl.opengl.GL45C;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A version of {@link VertexBuffer} which allows uploading {@link ByteBuffer}s directly.
|
||||||
|
*
|
||||||
|
* This should probably be its own class (rather than subclassing), but I need access to {@link VertexBuffer#drawWithShader}.
|
||||||
|
*/
|
||||||
|
public class DirectVertexBuffer extends VertexBuffer
|
||||||
|
{
|
||||||
|
private static final boolean HAS_DSA;
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
var capabilities = GL.getCapabilities();
|
||||||
|
HAS_DSA = capabilities.OpenGL45 || capabilities.GL_ARB_direct_state_access;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DirectVertexBuffer()
|
||||||
|
{
|
||||||
|
if( HAS_DSA )
|
||||||
|
{
|
||||||
|
RenderSystem.glDeleteBuffers( vertextBufferId );
|
||||||
|
vertextBufferId = GL45C.glCreateBuffers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void upload( int vertexCount, VertexFormat.Mode mode, VertexFormat format, ByteBuffer buffer )
|
||||||
|
{
|
||||||
|
RenderSystem.assertOnRenderThread();
|
||||||
|
|
||||||
|
if( HAS_DSA )
|
||||||
|
{
|
||||||
|
GL45C.glNamedBufferData( vertextBufferId, buffer, GL15.GL_STATIC_DRAW );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BufferUploader.reset();
|
||||||
|
bind();
|
||||||
|
RenderSystem.glBufferData( GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW );
|
||||||
|
unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.format = format;
|
||||||
|
this.mode = mode;
|
||||||
|
indexCount = mode.indexCount( vertexCount );
|
||||||
|
indexType = VertexFormat.IndexType.SHORT;
|
||||||
|
sequentialIndices = true;
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,7 @@ package dan200.computercraft.shared.peripheral.monitor;
|
|||||||
|
|
||||||
import com.mojang.blaze3d.platform.GlStateManager;
|
import com.mojang.blaze3d.platform.GlStateManager;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
import com.mojang.blaze3d.vertex.VertexBuffer;
|
import dan200.computercraft.client.util.DirectVertexBuffer;
|
||||||
import dan200.computercraft.shared.common.ClientTerminal;
|
import dan200.computercraft.shared.common.ClientTerminal;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
@ -32,7 +32,7 @@ public final class ClientMonitor extends ClientTerminal
|
|||||||
|
|
||||||
public int tboBuffer;
|
public int tboBuffer;
|
||||||
public int tboTexture;
|
public int tboTexture;
|
||||||
public VertexBuffer buffer;
|
public DirectVertexBuffer buffer;
|
||||||
|
|
||||||
public ClientMonitor( boolean colour, TileMonitor origin )
|
public ClientMonitor( boolean colour, TileMonitor origin )
|
||||||
{
|
{
|
||||||
@ -81,7 +81,7 @@ public final class ClientMonitor extends ClientTerminal
|
|||||||
if( buffer != null ) return false;
|
if( buffer != null ) return false;
|
||||||
|
|
||||||
deleteBuffers();
|
deleteBuffers();
|
||||||
buffer = new VertexBuffer();
|
buffer = new DirectVertexBuffer();
|
||||||
addMonitor();
|
addMonitor();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -70,6 +70,11 @@ public class TileMonitor extends TileGeneric
|
|||||||
private int xIndex = 0;
|
private int xIndex = 0;
|
||||||
private int yIndex = 0;
|
private int yIndex = 0;
|
||||||
|
|
||||||
|
private BlockPos bbPos;
|
||||||
|
private BlockState bbState;
|
||||||
|
private int bbX, bbY, bbWidth, bbHeight;
|
||||||
|
private AABB boundingBox;
|
||||||
|
|
||||||
public TileMonitor( BlockEntityType<? extends TileMonitor> type, BlockPos pos, BlockState state, boolean advanced )
|
public TileMonitor( BlockEntityType<? extends TileMonitor> type, BlockPos pos, BlockState state, boolean advanced )
|
||||||
{
|
{
|
||||||
super( type, pos, state );
|
super( type, pos, state );
|
||||||
@ -620,9 +625,25 @@ public class TileMonitor extends TileGeneric
|
|||||||
@Override
|
@Override
|
||||||
public AABB getRenderBoundingBox()
|
public AABB getRenderBoundingBox()
|
||||||
{
|
{
|
||||||
|
// We attempt to cache the bounding box to save having to do property lookups (and allocations!) on every frame.
|
||||||
|
// Unfortunately the AABB does depend on quite a lot of state, so we need to add a bunch of extra fields -
|
||||||
|
// ideally these'd be a single object, but I don't think worth doing until Java has value types.
|
||||||
|
if( boundingBox != null && getBlockState().equals( bbState ) && getBlockPos().equals( bbPos ) &&
|
||||||
|
xIndex == bbX && yIndex == bbY && width == bbWidth && height == bbHeight )
|
||||||
|
{
|
||||||
|
return boundingBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
bbState = getBlockState();
|
||||||
|
bbPos = getBlockPos();
|
||||||
|
bbX = xIndex;
|
||||||
|
bbY = yIndex;
|
||||||
|
bbWidth = width;
|
||||||
|
bbHeight = height;
|
||||||
|
|
||||||
BlockPos startPos = toWorldPos( 0, 0 );
|
BlockPos startPos = toWorldPos( 0, 0 );
|
||||||
BlockPos endPos = toWorldPos( width, height );
|
BlockPos endPos = toWorldPos( width, height );
|
||||||
return new AABB(
|
return boundingBox = new AABB(
|
||||||
Math.min( startPos.getX(), endPos.getX() ),
|
Math.min( startPos.getX(), endPos.getX() ),
|
||||||
Math.min( startPos.getY(), endPos.getY() ),
|
Math.min( startPos.getY(), endPos.getY() ),
|
||||||
Math.min( startPos.getZ(), endPos.getZ() ),
|
Math.min( startPos.getZ(), endPos.getZ() ),
|
||||||
|
@ -5,13 +5,18 @@
|
|||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.util;
|
package dan200.computercraft.shared.util;
|
||||||
|
|
||||||
|
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
public class Palette
|
public class Palette
|
||||||
{
|
{
|
||||||
private static final int PALETTE_SIZE = 16;
|
private static final int PALETTE_SIZE = 16;
|
||||||
private final double[][] colours = new double[PALETTE_SIZE][3];
|
private final double[][] colours = new double[PALETTE_SIZE][3];
|
||||||
|
private final byte[][] byteColours = new byte[PALETTE_SIZE][4];
|
||||||
|
private final byte[][] greyByteColours = new byte[PALETTE_SIZE][4];
|
||||||
|
|
||||||
public static final Palette DEFAULT = new Palette();
|
public static final Palette DEFAULT = new Palette();
|
||||||
|
|
||||||
@ -19,16 +24,23 @@ public class Palette
|
|||||||
{
|
{
|
||||||
// Get the default palette
|
// Get the default palette
|
||||||
resetColours();
|
resetColours();
|
||||||
|
|
||||||
|
for( int i = 0; i < PALETTE_SIZE; i++ ) byteColours[i][3] = greyByteColours[i][3] = (byte) 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setColour( int i, double r, double g, double b )
|
public void setColour( int i, double r, double g, double b )
|
||||||
{
|
{
|
||||||
if( i >= 0 && i < colours.length )
|
if( i < 0 || i >= colours.length ) return;
|
||||||
{
|
colours[i][0] = r;
|
||||||
colours[i][0] = r;
|
colours[i][1] = g;
|
||||||
colours[i][1] = g;
|
colours[i][2] = b;
|
||||||
colours[i][2] = b;
|
|
||||||
}
|
byteColours[i][0] = (byte) (int) (r * 255);
|
||||||
|
byteColours[i][1] = (byte) (int) (g * 255);
|
||||||
|
byteColours[i][2] = (byte) (int) (b * 255);
|
||||||
|
|
||||||
|
byte grey = (byte) (int) ((r + g + b) / 3 * 255);
|
||||||
|
greyByteColours[i][0] = greyByteColours[i][1] = greyByteColours[i][2] = grey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setColour( int i, Colour colour )
|
public void setColour( int i, Colour colour )
|
||||||
@ -38,19 +50,29 @@ public class Palette
|
|||||||
|
|
||||||
public double[] getColour( int i )
|
public double[] getColour( int i )
|
||||||
{
|
{
|
||||||
if( i >= 0 && i < colours.length )
|
return i >= 0 && i < colours.length ? colours[i] : null;
|
||||||
{
|
}
|
||||||
return colours[i];
|
|
||||||
}
|
/**
|
||||||
return null;
|
* Get the colour as a set of bytes rather than floats. This is called frequently by {@link FixedWidthFontRenderer},
|
||||||
|
* as our vertex format uses bytes.
|
||||||
|
*
|
||||||
|
* This allows us to do the conversion once (when setting the colour) rather than for every vertex, at the cost of
|
||||||
|
* some memory overhead.
|
||||||
|
*
|
||||||
|
* @param i The colour index.
|
||||||
|
* @param greyscale Whether this number should be converted to greyscale.
|
||||||
|
* @return The number as a tuple of bytes.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public byte[] getByteColour( int i, boolean greyscale )
|
||||||
|
{
|
||||||
|
return greyscale ? greyByteColours[i] : byteColours[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetColour( int i )
|
public void resetColour( int i )
|
||||||
{
|
{
|
||||||
if( i >= 0 && i < colours.length )
|
if( i >= 0 && i < colours.length ) setColour( i, Colour.VALUES[i] );
|
||||||
{
|
|
||||||
setColour( i, Colour.VALUES[i] );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetColours()
|
public void resetColours()
|
||||||
@ -89,9 +111,12 @@ public class Palette
|
|||||||
|
|
||||||
public void read( FriendlyByteBuf buffer )
|
public void read( FriendlyByteBuf buffer )
|
||||||
{
|
{
|
||||||
for( double[] colour : colours )
|
for( int i = 0; i < PALETTE_SIZE; i++ )
|
||||||
{
|
{
|
||||||
for( int i = 0; i < colour.length; i++ ) colour[i] = (buffer.readByte() & 0xFF) / 255.0;
|
double r = (buffer.readByte() & 0xFF) / 255.0;
|
||||||
|
double g = (buffer.readByte() & 0xFF) / 255.0;
|
||||||
|
double b = (buffer.readByte() & 0xFF) / 255.0;
|
||||||
|
setColour( i, r, g, b );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +142,8 @@ public class Palette
|
|||||||
|
|
||||||
for( int i = 0; i < colours.length; i++ )
|
for( int i = 0; i < colours.length; i++ )
|
||||||
{
|
{
|
||||||
colours[i] = decodeRGB8( rgb8[i] );
|
var colours = decodeRGB8( rgb8[i] );
|
||||||
|
setColour( i, colours[0], colours[1], colours[2] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,3 +11,11 @@ public net.minecraft.client.Minecraft f_91080_ # screen
|
|||||||
# SpeakerInstance/SpeakerManager
|
# SpeakerInstance/SpeakerManager
|
||||||
public com.mojang.blaze3d.audio.Channel m_83652_(I)V # pumpBuffers
|
public com.mojang.blaze3d.audio.Channel m_83652_(I)V # pumpBuffers
|
||||||
public net.minecraft.client.sounds.SoundEngine f_120223_ # executor
|
public net.minecraft.client.sounds.SoundEngine f_120223_ # executor
|
||||||
|
|
||||||
|
# DirectVertexBuffer
|
||||||
|
protected com.mojang.blaze3d.vertex.VertexBuffer f_166859_ # vertextBufferId
|
||||||
|
protected com.mojang.blaze3d.vertex.VertexBuffer f_166861_ # indexType
|
||||||
|
protected com.mojang.blaze3d.vertex.VertexBuffer f_166863_ # indexCount
|
||||||
|
protected com.mojang.blaze3d.vertex.VertexBuffer f_166864_ # mode
|
||||||
|
protected com.mojang.blaze3d.vertex.VertexBuffer f_166865_ # sequentialIndices
|
||||||
|
protected com.mojang.blaze3d.vertex.VertexBuffer f_85917_ # format
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#version 150
|
#version 150
|
||||||
|
|
||||||
|
#moj_import <fog.glsl>
|
||||||
|
|
||||||
#define FONT_WIDTH 6.0
|
#define FONT_WIDTH 6.0
|
||||||
#define FONT_HEIGHT 9.0
|
#define FONT_HEIGHT 9.0
|
||||||
|
|
||||||
@ -9,9 +11,15 @@ uniform int Height;
|
|||||||
uniform usamplerBuffer Tbo;
|
uniform usamplerBuffer Tbo;
|
||||||
uniform vec3 Palette[16];
|
uniform vec3 Palette[16];
|
||||||
|
|
||||||
in vec2 f_pos;
|
uniform vec4 ColorModulator;
|
||||||
|
uniform float FogStart;
|
||||||
|
uniform float FogEnd;
|
||||||
|
uniform vec4 FogColor;
|
||||||
|
|
||||||
out vec4 colour;
|
in float vertexDistance;
|
||||||
|
in vec2 fontPos;
|
||||||
|
|
||||||
|
out vec4 fragColor;
|
||||||
|
|
||||||
vec2 texture_corner(int index) {
|
vec2 texture_corner(int index) {
|
||||||
float x = 1.0 + float(index % 16) * (FONT_WIDTH + 2.0);
|
float x = 1.0 + float(index % 16) * (FONT_WIDTH + 2.0);
|
||||||
@ -20,7 +28,7 @@ vec2 texture_corner(int index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec2 term_pos = vec2(f_pos.x / FONT_WIDTH, f_pos.y / FONT_HEIGHT);
|
vec2 term_pos = vec2(fontPos.x / FONT_WIDTH, fontPos.y / FONT_HEIGHT);
|
||||||
vec2 corner = floor(term_pos);
|
vec2 corner = floor(term_pos);
|
||||||
|
|
||||||
ivec2 cell = ivec2(corner);
|
ivec2 cell = ivec2(corner);
|
||||||
@ -36,5 +44,7 @@ void main() {
|
|||||||
|
|
||||||
vec2 pos = (term_pos - corner) * vec2(FONT_WIDTH, FONT_HEIGHT);
|
vec2 pos = (term_pos - corner) * vec2(FONT_WIDTH, FONT_HEIGHT);
|
||||||
vec4 img = texture(Sampler0, (texture_corner(character) + pos) / 256.0);
|
vec4 img = texture(Sampler0, (texture_corner(character) + pos) / 256.0);
|
||||||
colour = vec4(mix(Palette[bg], img.rgb * Palette[fg], img.a * mult), 1.0);
|
vec4 colour = vec4(mix(Palette[bg], img.rgb * Palette[fg], img.a * mult), 1.0) * ColorModulator;
|
||||||
|
|
||||||
|
fragColor = linear_fog(colour, vertexDistance, FogStart, FogEnd, FogColor);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,13 @@
|
|||||||
"uniforms": [
|
"uniforms": [
|
||||||
{ "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
|
{ "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
|
||||||
{ "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
|
{ "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
|
||||||
|
{ "name": "IViewRotMat", "type": "matrix3x3", "count": 9, "values": [ 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 ] },
|
||||||
|
{ "name": "ColorModulator", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0, 1.0 ] },
|
||||||
|
{ "name": "FogStart", "type": "float", "count": 1, "values": [ 0.0 ] },
|
||||||
|
{ "name": "FogEnd", "type": "float", "count": 1, "values": [ 1.0 ] },
|
||||||
|
{ "name": "FogColor", "type": "float", "count": 4, "values": [ 0.0, 0.0, 0.0, 0.0 ] },
|
||||||
|
{ "name": "FogShape", "type": "int", "count": 1, "values": [ 0 ] },
|
||||||
|
|
||||||
{ "name": "Width", "type": "int", "count": 1, "values": [ 1 ] },
|
{ "name": "Width", "type": "int", "count": 1, "values": [ 1 ] },
|
||||||
{ "name": "Height", "type": "int", "count": 1, "values": [ 1 ] },
|
{ "name": "Height", "type": "int", "count": 1, "values": [ 1 ] },
|
||||||
{ "name": "Tbo", "type": "int", "count": 1, "values": [ 3 ] }
|
{ "name": "Tbo", "type": "int", "count": 1, "values": [ 3 ] }
|
||||||
|
@ -1,14 +1,21 @@
|
|||||||
#version 150
|
#version 150
|
||||||
|
|
||||||
|
#moj_import <fog.glsl>
|
||||||
|
|
||||||
in vec3 Position;
|
in vec3 Position;
|
||||||
in vec2 UV0;
|
in vec2 UV0;
|
||||||
|
|
||||||
uniform mat4 ModelViewMat;
|
uniform mat4 ModelViewMat;
|
||||||
uniform mat4 ProjMat;
|
uniform mat4 ProjMat;
|
||||||
|
uniform mat3 IViewRotMat;
|
||||||
|
uniform int FogShape;
|
||||||
|
|
||||||
out vec2 f_pos;
|
out float vertexDistance;
|
||||||
|
out vec2 fontPos;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = ProjMat * ModelViewMat * vec4(Position, 1);
|
gl_Position = ProjMat * ModelViewMat * vec4(Position, 1);
|
||||||
f_pos = UV0;
|
|
||||||
|
vertexDistance = fog_distance(ModelViewMat, IViewRotMat * Position, FogShape);
|
||||||
|
fontPos = UV0;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"vertex": "minecraft:position_color_tex",
|
|
||||||
"fragment": "minecraft:position_color_tex",
|
|
||||||
"attributes": [ "Position", "Color", "UV0" ],
|
|
||||||
"samplers": [ { "name": "Sampler0" } ],
|
|
||||||
"uniforms": [
|
|
||||||
{ "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
|
|
||||||
{ "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
|
|
||||||
{ "name": "ColorModulator", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0, 1.0 ] }
|
|
||||||
]
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user