1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-08-28 00:12:16 +00:00

[Iris] Merge Rendering Experiments to 1.18.2 (#78)

* Quick and dirty test.

- VBO monitor renderer path has been hijacked to test not using VBOs,
 instead we recreate the terminal geometry every frame.
- Add an explicit call the BufferSource.endBatch(). This actually fixes
 the incompatibility with Batched Entity Rendering. Who knew it was that
 easy?

 Results: works with Iris without shaders enabled.

* Use entity RenderType for rendering terminals in world.

- FixedWidthFontRenderer now emits quads and fills out all the vertex
 elements needed for the entity vertex format, which is, well, *all* of
 them.
- FixedWidthFontRenderer now takes a PoseStack so it can offset the char
 quads from the background.
- TERMINAL_MODE changed to quads so remaining custom RenderTypes work
 with FWFR.

New progress at this commit:
- Iris and Canvas both render the hi-jacked VBO backend properly.

Issues:
- Char quads have a blacker background than empty quads due to
 mismatched lightmaps.
- Items in hand have improper normals.
- TBO renderer is untested. Need to make sure it wasn't broken.

* More stuff

Progress:
- "VBO" code path now works fine with shaders.
- Printout GUI has lightmap issue.
- Pocket computer frames don't have right normals in world.
- Pocket computer lights don't work.

TODOs:
- Investigate whether VBOs can be used again without breaking compat.
If not, the code path needs to be renamed and the code for managing VBO
resources should be removed.
- Make sure TBO code path still works. Wouldn't be surprised if I broke
something there.

* Found a new rendertype for monitors, fixed normals

Progress:
- Monitors render fullbright in every direction.
- Normals are right on pocket computers and printouts, so lighting
  effects like directional light and shadow maps looks correct.
- BEST monitor renderer settings will detect shader mods and
  automatically enable shader compatible code path.

Details:
- The "textIntensity" rendertype is exactaly what we need for monitors.
  It's shader doesn't apply a directional light so monitors look
  fullbright consistent no matter what direction they're facing.
- Consolidated all references to rendertypes into RenderTypes class.
- Improved consistency of rendering classes. Methods pass a PoseStack
  instead of a Matrix4f down the chain where possible so that normals
  can be calculated, and most rendering classes now fill out all vertex
  elements so they can be used with any vanilla vertex format.
- Rendering methods should prefer to take a VertexConsumer rather than a
  BufferSource, the caller should provide appropriate buffer as that's
  where the context for buffer choice is.

TODO:
- Investigate re-enabling VBOs, and, if not an option, clean up naming
  and VBO related resource code.

* Re-enable vbos

Things were extremely slow without them in torture tests. They seem to
work fine with Iris. Will need to test with Canvas too. I don't know why
that hack with the inverse view rotation uniform works but fog doesn't
render correctly without it.

Unfortunately, the z-offset method does cause visible artifacts.
Background quads can sometimes be seen under the edges of adjacant
characters, giving the monitor a stitched together look. Will have to
investigate splitting all the background and char quads into two draw
calls and using glPolygonOffset on the characters :( which probably
means two vbos :( :(

Co-authored-by: Toad-Dev <748280+toad-dev@users.noreply.github.com>
This commit is contained in:
Merith 2022-03-27 15:13:53 -07:00 committed by GitHub
parent 12a5f7daeb
commit d8bb05f30e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 278 additions and 293 deletions

View File

@ -5,8 +5,10 @@
*/ */
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix3f;
import com.mojang.math.Matrix4f; import com.mojang.math.Matrix4f;
import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.client.render.RenderTypes; import dan200.computercraft.client.render.RenderTypes;
@ -15,7 +17,7 @@ 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.client.renderer.MultiBufferSource;
import net.minecraft.resources.ResourceLocation; import net.minecraft.client.renderer.texture.OverlayTexture;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -34,14 +36,10 @@ import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMA
* </li> * </li>
* <li>{@link #drawTerminal}: Draw a terminal with a cursor. This is used by the various computer GUIs to render the * <li>{@link #drawTerminal}: Draw a terminal with a cursor. This is used by the various computer GUIs to render the
* whole term.</li> * whole term.</li>
* <li>{@link #drawBlocker}: When rendering a terminal using {@link RenderTypes#TERMINAL_WITHOUT_DEPTH} you need to
* render an additional "depth blocker" on top of the monitor.</li>
* </ul> * </ul>
*/ */
public final class FixedWidthFontRenderer public final class FixedWidthFontRenderer
{ {
public static final ResourceLocation FONT = new ResourceLocation( "computercraft", "textures/gui/term_font.png" );
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; public static final float WIDTH = 256.0f;
@ -49,6 +47,8 @@ public final class FixedWidthFontRenderer
public static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH; public static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH;
public static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH; public static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH;
public static final float Z_EPSILON = 0.001f;
private FixedWidthFontRenderer() private FixedWidthFontRenderer()
{ {
} }
@ -63,7 +63,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( PoseStack transform, VertexConsumer buffer, float x, float y, int index, float r, float g, float b, 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,25 +74,25 @@ 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(); Matrix4f matrix = transform.last().pose();
buffer.vertex( transform, x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).uv( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).uv2( light ).endVertex(); Matrix3f normalMatrix = transform.last().normal();
buffer.vertex( transform, x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).uv( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).uv2( light ).endVertex(); vertex( matrix, normalMatrix, buffer, x, y, Z_EPSILON, r, g, b, xStart / WIDTH, yStart / 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(); vertex( matrix, normalMatrix, buffer, x, y + FONT_HEIGHT, Z_EPSILON, r, g, b, xStart / WIDTH, (yStart + FONT_HEIGHT) / 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(); vertex( matrix, normalMatrix, buffer, x + FONT_WIDTH, y + FONT_HEIGHT, Z_EPSILON, r, g, b, (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH, light );
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(); vertex( matrix, normalMatrix, buffer, x + FONT_WIDTH, y, Z_EPSILON, r, g, b, (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH, light );
} }
private static void drawQuad( Matrix4f transform, VertexConsumer buffer, float x, float y, float width, float height, float r, float g, float b ) private static void drawQuad( PoseStack transform, VertexConsumer buffer, float x, float y, float width, float height, float r, float g, float b, int light )
{ {
buffer.vertex( transform, x, y, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_START, BACKGROUND_START ).endVertex(); Matrix4f matrix = transform.last().pose();
buffer.vertex( transform, x, y + height, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_START, BACKGROUND_END ).endVertex(); Matrix3f normalMatrix = transform.last().normal();
buffer.vertex( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_START ).endVertex(); vertex( matrix, normalMatrix, buffer, x, y, 0, r, g, b, BACKGROUND_START, BACKGROUND_START, light );
buffer.vertex( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_START ).endVertex(); vertex( matrix, normalMatrix, buffer, x, y + height, 0, r, g, b, BACKGROUND_START, BACKGROUND_END, light );
buffer.vertex( transform, x, y + height, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_START, BACKGROUND_END ).endVertex(); vertex( matrix, normalMatrix, buffer, x + width, y + height, 0, r, g, b, BACKGROUND_END, BACKGROUND_END, light );
buffer.vertex( transform, x + width, y + height, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_END ).endVertex(); vertex( matrix, normalMatrix, buffer, x + width, y, 0, r, g, b, BACKGROUND_END, BACKGROUND_START, light );
} }
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( PoseStack transform, VertexConsumer buffer, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex, int light )
{ {
double[] colour = palette.getColour( getColour( colourIndex, Colour.BLACK ) ); double[] colour = palette.getColour( getColour( colourIndex, Colour.BLACK ) );
float r, g, b; float r, g, b;
@ -107,23 +107,23 @@ public final class FixedWidthFontRenderer
b = (float) colour[2]; b = (float) colour[2];
} }
drawQuad( transform, buffer, x, y, width, height, r, g, b ); drawQuad( transform, buffer, x, y, width, height, r, g, b, light );
} }
private static void drawBackground( private static void drawBackground(
@Nonnull Matrix4f transform, @Nonnull VertexConsumer renderer, float x, float y, @Nonnull PoseStack transform, @Nonnull VertexConsumer buffer, 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( transform, buffer, 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( transform, buffer, 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 +136,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( transform, buffer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour, light );
} }
blockColour = colourIndex; blockColour = colourIndex;
@ -145,19 +145,19 @@ 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( transform, buffer, 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 PoseStack transform, @Nonnull VertexConsumer buffer, 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( transform, buffer, 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++ )
@ -178,15 +178,15 @@ public final class FixedWidthFontRenderer
// 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( transform, buffer, x + i * FONT_WIDTH, y, index, r, g, b, light );
} }
} }
public static void drawTerminalWithoutCursor( public static void drawTerminalWithoutCursor(
@Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y, @Nonnull PoseStack transform, @Nonnull VertexConsumer 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, int light
) )
{ {
Palette palette = terminal.getPalette(); Palette palette = terminal.getPalette();
@ -196,13 +196,13 @@ public final class FixedWidthFontRenderer
drawBackground( drawBackground(
transform, buffer, x, y - topMarginSize, transform, buffer, x, y - topMarginSize,
terminal.getBackgroundColourLine( 0 ), palette, greyscale, terminal.getBackgroundColourLine( 0 ), palette, greyscale,
leftMarginSize, rightMarginSize, topMarginSize leftMarginSize, rightMarginSize, topMarginSize, light
); );
drawBackground( drawBackground(
transform, buffer, x, y + height * FONT_HEIGHT, transform, buffer, x, y + height * FONT_HEIGHT,
terminal.getBackgroundColourLine( height - 1 ), palette, greyscale, terminal.getBackgroundColourLine( height - 1 ), palette, greyscale,
leftMarginSize, rightMarginSize, bottomMarginSize leftMarginSize, rightMarginSize, bottomMarginSize, light
); );
// The main text // The main text
@ -217,7 +217,7 @@ public final class FixedWidthFontRenderer
} }
public static void drawCursor( public static void drawCursor(
@Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y, @Nonnull PoseStack transform, @Nonnull VertexConsumer buffer, float x, float y,
@Nonnull Terminal terminal, boolean greyscale @Nonnull Terminal terminal, boolean greyscale
) )
{ {
@ -247,42 +247,44 @@ public final class FixedWidthFontRenderer
} }
public static void drawTerminal( public static void drawTerminal(
@Nonnull Matrix4f transform, @Nonnull VertexConsumer buffer, float x, float y, @Nonnull PoseStack transform, @Nonnull VertexConsumer 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, int light
) )
{ {
drawTerminalWithoutCursor( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize ); drawTerminalWithoutCursor( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize, light );
drawCursor( transform, buffer, x, y, terminal, greyscale ); drawCursor( transform, buffer, x, y, terminal, greyscale );
} }
public static void drawTerminal( // Called by WidgetTerminal
@Nonnull Matrix4f transform, float x, float y, @Nonnull Terminal terminal, boolean greyscale, public static void drawTerminalImmediate(
@Nonnull PoseStack transform, float x, float y, @Nonnull Terminal terminal, boolean greyscale,
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
) )
{ {
MultiBufferSource.BufferSource renderer = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() ); MultiBufferSource.BufferSource renderer = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() );
VertexConsumer buffer = renderer.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH ); VertexConsumer buffer = renderer.getBuffer( RenderTypes.GUI_TERMINAL );
drawTerminal( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize ); drawTerminal( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize, FULL_BRIGHT_LIGHTMAP );
renderer.endBatch(); renderer.endBatch();
} }
public static void drawEmptyTerminal( @Nonnull Matrix4f transform, @Nonnull MultiBufferSource renderer, float x, float y, float width, float height ) public static void drawEmptyTerminal( @Nonnull PoseStack transform, @Nonnull VertexConsumer buffer, float x, float y, float width, float height, int light )
{ {
Colour colour = Colour.BLACK; Colour colour = Colour.BLACK;
drawQuad( transform, renderer.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() ); drawQuad( transform, buffer, x, y, width, height, colour.getR(), colour.getG(), colour.getB(), light );
} }
public static void drawEmptyTerminal( @Nonnull Matrix4f transform, float x, float y, float width, float height ) public static void drawEmptyTerminalImmediate( @Nonnull PoseStack transform, float x, float y, float width, float height )
{ {
MultiBufferSource.BufferSource renderer = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() ); MultiBufferSource.BufferSource renderer = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() );
drawEmptyTerminal( transform, renderer, x, y, width, height ); VertexConsumer buffer = renderer.getBuffer( RenderTypes.GUI_TERMINAL );
drawEmptyTerminal( transform, buffer, x, y, width, height, FULL_BRIGHT_LIGHTMAP );
renderer.endBatch(); renderer.endBatch();
} }
public static void drawBlocker( @Nonnull Matrix4f transform, @Nonnull MultiBufferSource renderer, float x, float y, float width, float height ) private static void vertex( Matrix4f poseMatrix, Matrix3f normalMatrix, VertexConsumer buffer, float x, float y, float z, float r, float g, float b, float u, float v, int light )
{ {
Colour colour = Colour.BLACK; buffer.vertex( poseMatrix, x, y, z ).color( r, g, b, 1.0f ).uv( u, v ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( light ).normal( normalMatrix, 0f, 0f, 1f ).endVertex();
drawQuad( transform, renderer.getBuffer( RenderTypes.TERMINAL_BLOCKER ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() );
} }
} }

View File

@ -76,7 +76,7 @@ public final class GuiComputer<T extends ContainerComputerBase> extends Computer
public void renderBg( @Nonnull PoseStack stack, float partialTicks, int mouseX, int mouseY ) public void renderBg( @Nonnull PoseStack stack, float partialTicks, int mouseX, int mouseY )
{ {
// Draw a border around the terminal // Draw a border around the terminal
ComputerBorderRenderer.render( ComputerBorderRenderer.renderFromGui(
ComputerBorderRenderer.getTexture( family ), terminal.x, terminal.y, getBlitOffset(), ComputerBorderRenderer.getTexture( family ), terminal.x, terminal.y, getBlitOffset(),
RenderTypes.FULL_BRIGHT_LIGHTMAP, terminal.getWidth(), terminal.getHeight() RenderTypes.FULL_BRIGHT_LIGHTMAP, terminal.getWidth(), terminal.getHeight()
); );

View File

@ -5,10 +5,10 @@
*/ */
package dan200.computercraft.client.gui; package dan200.computercraft.client.gui;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.math.Matrix4f; import com.mojang.blaze3d.vertex.VertexConsumer;
import dan200.computercraft.client.render.RenderTypes;
import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.common.ContainerHeldItem;
import dan200.computercraft.shared.media.items.ItemPrintout; import dan200.computercraft.shared.media.items.ItemPrintout;
@ -100,13 +100,14 @@ public class GuiPrintout extends AbstractContainerScreen<ContainerHeldItem>
protected void renderBg( @Nonnull PoseStack transform, float partialTicks, int mouseX, int mouseY ) protected void renderBg( @Nonnull PoseStack transform, float partialTicks, int mouseX, int mouseY )
{ {
// Draw the printout // Draw the printout
RenderSystem.setShaderColor( 1.0f, 1.0f, 1.0f, 1.0f );
RenderSystem.enableDepthTest();
MultiBufferSource.BufferSource renderer = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() ); MultiBufferSource.BufferSource renderer = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() );
Matrix4f matrix = transform.last().pose();
drawBorder( matrix, renderer, leftPos, topPos, getBlitOffset(), page, pages, book, FULL_BRIGHT_LIGHTMAP ); VertexConsumer borderBuffer = renderer.getBuffer( RenderTypes.GUI_PRINTOUT_BACKGROUND );
drawText( matrix, renderer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * page, FULL_BRIGHT_LIGHTMAP, text, colours ); drawBorder( transform, borderBuffer, leftPos, topPos, getBlitOffset(), page, pages, book, FULL_BRIGHT_LIGHTMAP );
VertexConsumer textBuffer = renderer.getBuffer( RenderTypes.GUI_PRINTOUT_TEXT );
drawText( transform, textBuffer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * page, FULL_BRIGHT_LIGHTMAP, text, colours );
renderer.endBatch(); renderer.endBatch();
} }

View File

@ -6,7 +6,6 @@
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.math.Matrix4f;
import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ClientComputer;
@ -313,15 +312,14 @@ public class WidgetTerminal extends AbstractWidget
public void render( @Nonnull PoseStack transform, int mouseX, int mouseY, float partialTicks ) public void render( @Nonnull PoseStack transform, int mouseX, int mouseY, float partialTicks )
{ {
if( !visible ) return; if( !visible ) return;
Matrix4f matrix = transform.last().pose();
Terminal terminal = computer.getTerminal(); Terminal terminal = computer.getTerminal();
if( terminal != null ) if( terminal != null )
{ {
FixedWidthFontRenderer.drawTerminal( matrix, innerX, innerY, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN ); FixedWidthFontRenderer.drawTerminalImmediate( transform, innerX, innerY, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN );
} }
else else
{ {
FixedWidthFontRenderer.drawEmptyTerminal( matrix, x, y, width, height ); FixedWidthFontRenderer.drawEmptyTerminalImmediate( transform, x, y, width, height );
} }
} }

View File

@ -5,13 +5,15 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.blaze3d.vertex.Tesselator;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix3f;
import com.mojang.math.Matrix4f; import com.mojang.math.Matrix4f;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -53,13 +55,13 @@ public class ComputerBorderRenderer
public static final int TEX_SIZE = 256; public static final int TEX_SIZE = 256;
private static final float TEX_SCALE = 1 / (float) TEX_SIZE; private static final float TEX_SCALE = 1 / (float) TEX_SIZE;
private final Matrix4f transform; private final PoseStack transform;
private final VertexConsumer builder; private final VertexConsumer builder;
private final int light; private final int light;
private final int z; private final int z;
private final float r, g, b; private final float r, g, b;
public ComputerBorderRenderer( Matrix4f transform, VertexConsumer builder, int z, int light, float r, float g, float b ) public ComputerBorderRenderer( PoseStack transform, VertexConsumer builder, int z, int light, float r, float g, float b )
{ {
this.transform = transform; this.transform = transform;
this.builder = builder; this.builder = builder;
@ -86,20 +88,18 @@ public class ComputerBorderRenderer
} }
} }
public static RenderType getRenderType( ResourceLocation location ) public static void renderFromGui( ResourceLocation location, int x, int y, int z, int light, int width, int height )
{ {
// See note in RenderTypes about why we use text rather than anything intuitive. PoseStack identityStack = new PoseStack();
return RenderType.text( location ); MultiBufferSource.BufferSource renderer = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() );
render(
identityStack, renderer.getBuffer( RenderTypes.guiComputerBorder( location ) ),
x, y, z, light, width, height, false, 1, 1, 1
);
renderer.endBatch();
} }
public static void render( ResourceLocation location, int x, int y, int z, int light, int width, int height ) public static void render( PoseStack transform, VertexConsumer buffer, int x, int y, int z, int light, int width, int height, boolean withLight, float r, float g, float b )
{
MultiBufferSource.BufferSource source = MultiBufferSource.immediate( Tesselator.getInstance().getBuilder() );
render( IDENTITY, source.getBuffer( getRenderType( location ) ), x, y, z, light, width, height, false, 1, 1, 1 );
source.endBatch();
}
public static void render( Matrix4f transform, VertexConsumer buffer, int x, int y, int z, int light, int width, int height, boolean withLight, float r, float g, float b )
{ {
new ComputerBorderRenderer( transform, buffer, z, light, r, g, b ).doRender( x, y, width, height, withLight ); new ComputerBorderRenderer( transform, buffer, z, light, r, g, b ).doRender( x, y, width, height, withLight );
} }
@ -151,9 +151,11 @@ public class ComputerBorderRenderer
private void renderTexture( int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight ) private void renderTexture( int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight )
{ {
builder.vertex( transform, x, y + height, z ).color( r, g, b, 1.0f ).uv( u * TEX_SCALE, (v + textureHeight) * TEX_SCALE ).uv2( light ).endVertex(); Matrix4f poseMatrix = transform.last().pose();
builder.vertex( transform, x + width, y + height, z ).color( r, g, b, 1.0f ).uv( (u + textureWidth) * TEX_SCALE, (v + textureHeight) * TEX_SCALE ).uv2( light ).endVertex(); Matrix3f normalMatrix = transform.last().normal();
builder.vertex( transform, x + width, y, z ).color( r, g, b, 1.0f ).uv( (u + textureWidth) * TEX_SCALE, v * TEX_SCALE ).uv2( light ).endVertex(); builder.vertex( poseMatrix, x, y + height, z ).color( r, g, b, 1.0f ).uv( u * TEX_SCALE, (v + textureHeight) * TEX_SCALE ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( light ).normal( normalMatrix, 0f, 0f, 1f ).endVertex();
builder.vertex( transform, x, y, z ).color( r, g, b, 1.0f ).uv( u * TEX_SCALE, v * TEX_SCALE ).uv2( light ).endVertex(); builder.vertex( poseMatrix, x + width, y + height, z ).color( r, g, b, 1.0f ).uv( (u + textureWidth) * TEX_SCALE, (v + textureHeight) * TEX_SCALE ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( light ).normal( normalMatrix, 0f, 0f, 1f ).endVertex();
builder.vertex( poseMatrix, x + width, y, z ).color( r, g, b, 1.0f ).uv( (u + textureWidth) * TEX_SCALE, v * TEX_SCALE ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( light ).normal( normalMatrix, 0f, 0f, 1f ).endVertex();
builder.vertex( poseMatrix, x, y, z ).color( r, g, b, 1.0f ).uv( u * TEX_SCALE, v * TEX_SCALE ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( light ).normal( normalMatrix, 0f, 0f, 1f ).endVertex();
} }
} }

View File

@ -6,6 +6,7 @@
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.vertex.*; import com.mojang.blaze3d.vertex.*;
import com.mojang.math.Matrix3f;
import com.mojang.math.Matrix4f; import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f; import com.mojang.math.Vector3f;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
@ -16,12 +17,13 @@ import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Colour;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
import static dan200.computercraft.client.render.ComputerBorderRenderer.*; import static dan200.computercraft.client.render.ComputerBorderRenderer.*;
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
/** /**
* Emulates map rendering for pocket computers. * Emulates map rendering for pocket computers.
@ -63,7 +65,9 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
transform.scale( 0.5f, 0.5f, 0.5f ); transform.scale( 0.5f, 0.5f, 0.5f );
float scale = 0.75f / Math.max( width + BORDER * 2, height + BORDER * 2 + LIGHT_HEIGHT ); float scale = 0.75f / Math.max( width + BORDER * 2, height + BORDER * 2 + LIGHT_HEIGHT );
transform.scale( scale, scale, -1.0f ); // Avoid PoseStack#scale to preserve normal matrix, and fix the normals ourselves.
transform.last().pose().multiply( Matrix4f.createScaleMatrix( scale, scale, -1.0f ) );
transform.last().normal().mul( -1.0f );
transform.translate( -0.5 * width, -0.5 * height, 0 ); transform.translate( -0.5 * width, -0.5 * height, 0 );
// Render the main frame // Render the main frame
@ -71,31 +75,32 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
ComputerFamily family = item.getFamily(); ComputerFamily family = item.getFamily();
int frameColour = item.getColour( stack ); int frameColour = item.getColour( stack );
Matrix4f matrix = transform.last().pose(); renderFrame( transform, renderer, family, frameColour, light, width, height );
renderFrame( matrix, renderer, 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( transform, renderer, lightColour, width, height );
VertexConsumer buffer = renderer.getBuffer( RenderTypes.ITEM_POCKET_TERMINAL );
if( computer != null && terminal != null ) if( computer != null && terminal != null )
{ {
FixedWidthFontRenderer.drawTerminal( FixedWidthFontRenderer.drawTerminal(
matrix, renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ), transform, buffer,
MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN, FULL_BRIGHT_LIGHTMAP
); );
FixedWidthFontRenderer.drawBlocker( transform.last().pose(), renderer, 0, 0, width, height );
} }
else else
{ {
FixedWidthFontRenderer.drawEmptyTerminal( matrix, 0, 0, width, height ); FixedWidthFontRenderer.drawEmptyTerminal(
transform, buffer,
0, 0, width, height, 0 );
} }
transform.popPose(); transform.popPose();
} }
private static void renderFrame( Matrix4f transform, MultiBufferSource render, ComputerFamily family, int colour, int light, int width, int height ) private static void renderFrame( PoseStack transform, MultiBufferSource renderer, ComputerFamily family, int colour, int light, int width, int height )
{ {
ResourceLocation texture = colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family ); ResourceLocation texture = colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family );
@ -103,20 +108,23 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
float g = ((colour >>> 8) & 0xFF) / 255.0f; float g = ((colour >>> 8) & 0xFF) / 255.0f;
float b = (colour & 0xFF) / 255.0f; float b = (colour & 0xFF) / 255.0f;
ComputerBorderRenderer.render( transform, render.getBuffer( ComputerBorderRenderer.getRenderType( texture ) ), 0, 0, 0, light, width, height, true, r, g, b ); VertexConsumer buffer = renderer.getBuffer( RenderTypes.itemPocketBorder( texture ) );
ComputerBorderRenderer.render( transform, buffer, 0, 0, 0, light, width, height, true, r, g, b );
} }
private static void renderLight( Matrix4f transform, MultiBufferSource render, int colour, int width, int height ) private static void renderLight( PoseStack transform, MultiBufferSource renderer, int colour, int width, int height )
{ {
float r = ((colour >>> 16) & 0xFF) / 255.0f; float r = ((colour >>> 16) & 0xFF) / 255.0f;
float g = ((colour >>> 8) & 0xFF) / 255.0f; float g = ((colour >>> 8) & 0xFF) / 255.0f;
float b = (colour & 0xFF) / 255.0f; float b = (colour & 0xFF) / 255.0f;
float z = 0.001f; float z = 0.001f;
VertexConsumer buffer = render.getBuffer( RenderTypes.POSITION_COLOR ); VertexConsumer buffer = renderer.getBuffer( RenderTypes.ITEM_POCKET_LIGHT );
buffer.vertex( transform, width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).endVertex(); Matrix4f poseMatrix = transform.last().pose();
buffer.vertex( transform, width, height + LIGHT_HEIGHT + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).endVertex(); Matrix3f normalMatrix = transform.last().normal();
buffer.vertex( transform, width, height + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).endVertex(); buffer.vertex( poseMatrix, width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).uv( BACKGROUND_START, BACKGROUND_START ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( FULL_BRIGHT_LIGHTMAP ).normal( normalMatrix, 0f, 0f, 1f ).endVertex();
buffer.vertex( transform, width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).endVertex(); buffer.vertex( poseMatrix, width, height + LIGHT_HEIGHT + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).uv( BACKGROUND_START, BACKGROUND_END ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( FULL_BRIGHT_LIGHTMAP ).normal( normalMatrix, 0f, 0f, 1f ).endVertex();
buffer.vertex( poseMatrix, width, height + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_END ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( FULL_BRIGHT_LIGHTMAP ).normal( normalMatrix, 0f, 0f, 1f ).endVertex();
buffer.vertex( poseMatrix, width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, z ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_START ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( FULL_BRIGHT_LIGHTMAP ).normal( normalMatrix, 0f, 0f, 1f ).endVertex();
} }
} }

View File

@ -29,32 +29,38 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
{ {
} }
public boolean renderInFrame( PoseStack matrixStack, MultiBufferSource consumerProvider, ItemStack stack, int light ) public boolean renderInFrame( PoseStack transform, MultiBufferSource renderer, ItemStack stack, int light )
{ {
if( !(stack.getItem() instanceof ItemPrintout) ) return false; if( !(stack.getItem() instanceof ItemPrintout) ) return false;
// Move a little bit forward to ensure we're not clipping with the frame // Move a little bit forward to ensure we're not clipping with the frame
matrixStack.translate( 0.0f, 0.0f, -0.001f ); transform.translate( 0.0f, 0.0f, -0.001f );
matrixStack.mulPose( Vector3f.ZP.rotationDegrees( 180f ) ); transform.mulPose( Vector3f.ZP.rotationDegrees( 180f ) );
matrixStack.scale( 0.95f, 0.95f, -0.95f ); // Avoid PoseStack#scale to preserve normal matrix, and fix the normals ourselves.
matrixStack.translate( -0.5f, -0.5f, 0.0f ); transform.last().pose().multiply( Matrix4f.createScaleMatrix( 0.95f, 0.95f, -0.95f ) );
transform.last().normal().mul( -1.0f );
drawPrintout( matrixStack, consumerProvider, stack, light ); //transform.last().normal().mul( -1.0f );
transform.translate( -0.5f, -0.5f, 0.0f );
drawPrintout( transform, renderer, stack, light );
return true; return true;
} }
@Override @Override
protected void renderItem( PoseStack transform, MultiBufferSource render, ItemStack stack, int light ) protected void renderItem( PoseStack transform, MultiBufferSource renderer, ItemStack stack, int light )
{ {
transform.mulPose( Vector3f.XP.rotationDegrees( 180f ) ); transform.mulPose( Vector3f.XP.rotationDegrees( 180f ) );
transform.scale( 0.42f, 0.42f, -0.42f ); // Avoid PoseStack#scale to preserve normal matrix, and fix the normals ourselves.
transform.last().pose().multiply( Matrix4f.createScaleMatrix( 0.42f, 0.42f, -0.42f ) );
transform.last().normal().mul( -1.0f );
transform.translate( -0.5f, -0.48f, 0.0f ); transform.translate( -0.5f, -0.48f, 0.0f );
drawPrintout( transform, render, stack, light ); drawPrintout( transform, renderer, stack, light );
} }
private static void drawPrintout( PoseStack transform, MultiBufferSource render, ItemStack stack, int light ) private static void drawPrintout( PoseStack transform, MultiBufferSource renderer, ItemStack stack, int light )
{ {
int pages = ItemPrintout.getPageCount( stack ); int pages = ItemPrintout.getPageCount( stack );
boolean book = ((ItemPrintout) stack.getItem()).getType() == ItemPrintout.Type.BOOK; boolean book = ((ItemPrintout) stack.getItem()).getType() == ItemPrintout.Type.BOOK;
@ -81,11 +87,13 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
transform.scale( scale, scale, scale ); transform.scale( scale, scale, scale );
transform.translate( (max - width) / 2.0, (max - height) / 2.0, 0.0 ); transform.translate( (max - width) / 2.0, (max - height) / 2.0, 0.0 );
Matrix4f matrix = transform.last().pose(); drawBorder(
drawBorder( matrix, render, 0, 0, -0.01f, 0, pages, book, light ); transform, renderer.getBuffer( RenderTypes.ITEM_PRINTOUT_BACKGROUND ),
0, 0, -0.01f, 0, pages, book, light
);
drawText( drawText(
matrix, render, X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, light, transform, renderer.getBuffer( RenderTypes.ITEM_PRINTOUT_TEXT ),
ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, light, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack )
); );
} }
} }

View File

@ -5,12 +5,14 @@
*/ */
package dan200.computercraft.client.render; package dan200.computercraft.client.render;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Matrix3f;
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.core.terminal.TextBuffer; import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.util.Palette; import dan200.computercraft.shared.util.Palette;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.texture.OverlayTexture;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE; import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE;
@ -54,9 +56,8 @@ 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( PoseStack transform, VertexConsumer buffer, int x, int y, int start, int light, TextBuffer[] text, TextBuffer[] colours )
{ {
VertexConsumer buffer = renderer.getBuffer( RenderTypes.PRINTOUT_TEXT );
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( transform, buffer,
@ -67,9 +68,8 @@ 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( PoseStack transform, VertexConsumer buffer, int x, int y, int start, int light, String[] text, String[] colours )
{ {
VertexConsumer buffer = renderer.getBuffer( RenderTypes.PRINTOUT_TEXT );
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( transform, buffer,
@ -81,13 +81,11 @@ 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( PoseStack transform, VertexConsumer buffer, 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 );
if( isBook ) if( isBook )
{ {
// Border // Border
@ -144,25 +142,29 @@ public final class PrintoutRenderer
} }
} }
private static void drawTexture( Matrix4f matrix, VertexConsumer buffer, float x, float y, float z, float u, float v, float width, float height, int light ) private static void drawTexture( PoseStack transform, VertexConsumer buffer, float x, float y, float z, float u, float v, float width, float height, int light )
{ {
vertex( buffer, matrix, x, y + height, z, u / BG_SIZE, (v + height) / BG_SIZE, light ); Matrix4f poseMatrix = transform.last().pose();
vertex( buffer, matrix, x + width, y + height, z, (u + width) / BG_SIZE, (v + height) / BG_SIZE, light ); Matrix3f normalMatrix = transform.last().normal();
vertex( buffer, matrix, x + width, y, z, (u + width) / BG_SIZE, v / BG_SIZE, light ); vertex( poseMatrix, normalMatrix, buffer, x, y + height, z, u / BG_SIZE, (v + height) / BG_SIZE, light );
vertex( buffer, matrix, x, y, z, u / BG_SIZE, v / BG_SIZE, light ); vertex( poseMatrix, normalMatrix, buffer, x + width, y + height, z, (u + width) / BG_SIZE, (v + height) / BG_SIZE, light );
vertex( poseMatrix, normalMatrix, buffer, x + width, y, z, (u + width) / BG_SIZE, v / BG_SIZE, light );
vertex( poseMatrix, normalMatrix, buffer, x, y, z, u / BG_SIZE, v / BG_SIZE, light );
} }
private static void drawTexture( Matrix4f matrix, VertexConsumer buffer, float x, float y, float z, float width, float height, float u, float v, float tWidth, float tHeight, int light ) private static void drawTexture( PoseStack transform, VertexConsumer buffer, float x, float y, float z, float width, float height, float u, float v, float tWidth, float tHeight, int light )
{ {
vertex( buffer, matrix, x, y + height, z, u / BG_SIZE, (v + tHeight) / BG_SIZE, light ); Matrix4f poseMatrix = transform.last().pose();
vertex( buffer, matrix, x + width, y + height, z, (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE, light ); Matrix3f normalMatrix = transform.last().normal();
vertex( buffer, matrix, x + width, y, z, (u + tWidth) / BG_SIZE, v / BG_SIZE, light ); vertex( poseMatrix, normalMatrix, buffer, x, y + height, z, u / BG_SIZE, (v + tHeight) / BG_SIZE, light );
vertex( buffer, matrix, x, y, z, u / BG_SIZE, v / BG_SIZE, light ); vertex( poseMatrix, normalMatrix, buffer, x + width, y + height, z, (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE, light );
vertex( poseMatrix, normalMatrix, buffer, x + width, y, z, (u + tWidth) / BG_SIZE, v / BG_SIZE, light );
vertex( poseMatrix, normalMatrix, buffer, x, y, z, u / BG_SIZE, v / BG_SIZE, light );
} }
private static void vertex( VertexConsumer buffer, Matrix4f matrix, float x, float y, float z, float u, float v, int light ) private static void vertex( Matrix4f poseMatrix, Matrix3f normalMatrix, VertexConsumer buffer, float x, float y, float z, float u, float v, int light )
{ {
buffer.vertex( matrix, x, y, z ).color( 255, 255, 255, 255 ).uv( u, v ).uv2( light ).endVertex(); buffer.vertex( poseMatrix, x, y, z ).color( 255, 255, 255, 255 ).uv( u, v ).overlayCoords( OverlayTexture.NO_OVERLAY ).uv2( light ).normal( normalMatrix, 0f, 0f, 1f ).endVertex();
} }
public static float offsetAt( int page ) public static float offsetAt( int page )

View File

@ -7,7 +7,7 @@ package dan200.computercraft.client.render;
import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.VertexFormat; import com.mojang.blaze3d.vertex.VertexFormat;
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;
@ -15,28 +15,41 @@ import net.minecraft.resources.ResourceLocation;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public class RenderTypes public class RenderTypes
{ {
public static final ResourceLocation FONT = new ResourceLocation( "computercraft", "textures/gui/term_font.png" );
public static final ResourceLocation PRINTOUT_BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/printout.png" );
public static final int FULL_BRIGHT_LIGHTMAP = (0xF << 4) | (0xF << 20); public static final int FULL_BRIGHT_LIGHTMAP = (0xF << 4) | (0xF << 20);
public static MonitorTextureBufferShader monitorTboShader;
public 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 MONITOR_TBO = Types.MONITOR_TBO;
public static final RenderType PRINTOUT_TEXT = Types.PRINTOUT_TEXT; public static final RenderType MONITOR = RenderType.textIntensity( FONT );
/** public static final RenderType ITEM_POCKET_TERMINAL = RenderType.textIntensity( FONT );
* This looks wrong (it should be POSITION_COLOR_TEX_LIGHTMAP surely!) but the fragment/vertex shader for that public static final RenderType ITEM_POCKET_LIGHT = RenderType.textIntensity( FONT );
* appear to entirely ignore the lightmap. public static final RenderType ITEM_PRINTOUT_BACKGROUND = RenderType.entityCutout( PRINTOUT_BACKGROUND );
* public static final RenderType ITEM_PRINTOUT_TEXT = RenderType.entityCutout( FONT );
* Note that vanilla maps do the same, so this isn't unreasonable.
*/
public static final RenderType PRINTOUT_BACKGROUND = RenderType.text( new ResourceLocation( "computercraft", "textures/gui/printout.png" ) );
public static final RenderType POSITION_COLOR = Types.POSITION_COLOR; public static final RenderType GUI_TERMINAL = RenderType.text( FONT );
public static final RenderType GUI_PRINTOUT_BACKGROUND = RenderType.text( PRINTOUT_BACKGROUND );
public static final RenderType GUI_PRINTOUT_TEXT = RenderType.text( FONT );
public static ShaderInstance getMonitorShader()
{
return GameRenderer.getRendertypeTextIntensityShader();
}
public static RenderType itemPocketBorder( ResourceLocation location )
{
return RenderType.entityCutout( location );
}
public static RenderType guiComputerBorder( ResourceLocation location )
{
return RenderType.text( location );
}
public static MonitorTextureBufferShader monitorTboShader;
@Nonnull @Nonnull
static MonitorTextureBufferShader getMonitorTextureBufferShader() static MonitorTextureBufferShader getMonitorTextureBufferShader()
@ -45,22 +58,12 @@ public class RenderTypes
return monitorTboShader; return monitorTboShader;
} }
@Nonnull
static ShaderInstance getTerminalShader()
{
if( terminalShader == null ) throw new NullPointerException( "MonitorTboShader has not been registered" );
return terminalShader;
}
private static final class Types extends RenderStateShard private static final class Types extends RenderStateShard
{ {
private static final RenderStateShard.TextureStateShard TERM_FONT_TEXTURE = new TextureStateShard( private static final RenderStateShard.TextureStateShard TERM_FONT_TEXTURE = new TextureStateShard(
FixedWidthFontRenderer.FONT, FONT,
false, false // blur, minimap false, false // blur, minimap
); );
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 );
static final RenderType MONITOR_TBO = RenderType.create( static final RenderType MONITOR_TBO = RenderType.create(
"monitor_tbo", DefaultVertexFormat.POSITION_TEX, VertexFormat.Mode.TRIANGLE_STRIP, 128, "monitor_tbo", DefaultVertexFormat.POSITION_TEX, VertexFormat.Mode.TRIANGLE_STRIP, 128,
@ -68,57 +71,6 @@ public class RenderTypes
RenderType.CompositeState.builder() RenderType.CompositeState.builder()
.setTextureState( TERM_FONT_TEXTURE ) .setTextureState( TERM_FONT_TEXTURE )
.setShaderState( new ShaderStateShard( RenderTypes::getMonitorTextureBufferShader ) ) .setShaderState( new ShaderStateShard( RenderTypes::getMonitorTextureBufferShader ) )
.setWriteMaskState( COLOR_WRITE )
.createCompositeState( false )
);
static final RenderType TERMINAL_WITHOUT_DEPTH = RenderType.create(
"terminal_without_depth", TERM_FORMAT, TERM_MODE, 1024,
false, false, // useDelegate, needsSorting
RenderType.CompositeState.builder()
.setTextureState( TERM_FONT_TEXTURE )
.setShaderState( TERM_SHADER )
.setWriteMaskState( COLOR_WRITE )
.createCompositeState( false )
);
static final RenderType TERMINAL_BLOCKER = RenderType.create(
"terminal_blocker", TERM_FORMAT, TERM_MODE, 256,
false, false, // useDelegate, needsSorting
RenderType.CompositeState.builder()
.setTextureState( TERM_FONT_TEXTURE )
.setShaderState( TERM_SHADER )
.setWriteMaskState( DEPTH_WRITE )
.createCompositeState( false )
);
static final RenderType TERMINAL_WITH_DEPTH = RenderType.create(
"terminal_with_depth", TERM_FORMAT, TERM_MODE, 1024,
false, false, // useDelegate, needsSorting
RenderType.CompositeState.builder()
.setTextureState( TERM_FONT_TEXTURE )
.setShaderState( TERM_SHADER )
.createCompositeState( false )
);
/**
* 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 )
); );

View File

@ -9,8 +9,8 @@ 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.*;
import com.mojang.math.Matrix3f;
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;
@ -23,7 +23,6 @@ import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.DirectionUtil;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -36,6 +35,7 @@ import javax.annotation.Nonnull;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*;
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonitor> public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonitor>
{ {
@ -43,10 +43,17 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonito
* {@link TileMonitor#RENDER_MARGIN}, but a tiny bit of additional padding to ensure that there is no space between * {@link TileMonitor#RENDER_MARGIN}, but a tiny bit of additional padding to ensure that there is no space between
* 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.05);
private static ByteBuffer tboContents; private static ByteBuffer tboContents;
private static final Matrix4f IDENTITY = Transformation.identity().getMatrix(); private static final Matrix3f IDENTITY;
static
{
Matrix3f identity = new Matrix3f();
identity.setIdentity();
IDENTITY = identity;
}
public TileEntityMonitorRenderer( BlockEntityRendererProvider.Context context ) public TileEntityMonitorRenderer( BlockEntityRendererProvider.Context context )
{ {
@ -110,44 +117,33 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonito
double xScale = xSize / pixelWidth; double xScale = xSize / pixelWidth;
double yScale = ySize / pixelHeight; double yScale = ySize / pixelHeight;
transform.pushPose(); transform.pushPose();
transform.scale( (float) xScale, (float) -yScale, 1.0f ); // Avoid PoseStack#scale to preserve normal matrix.
transform.last().pose().multiply( Matrix4f.createScaleMatrix( (float) xScale, (float) -yScale, 1.0f ) );
Matrix4f matrix = transform.last().pose(); renderTerminal( renderer, transform, originTerminal, (float) (MARGIN / xScale), (float) (MARGIN / yScale) );
renderTerminal( renderer, 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, as it's dynamic and so we'll end up refreshing far more than is
// reasonable. // reasonable.
FixedWidthFontRenderer.drawCursor( FixedWidthFontRenderer.drawCursor(
matrix, renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ), transform, renderer.getBuffer( RenderTypes.MONITOR ),
0, 0, terminal, !originTerminal.isColour() 0, 0, terminal, !originTerminal.isColour()
); );
transform.popPose(); transform.popPose();
FixedWidthFontRenderer.drawBlocker(
transform.last().pose(), renderer,
-MARGIN, MARGIN,
(float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)
);
// 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!
renderer.getBuffer( RenderType.solid() );
} }
else else
{ {
FixedWidthFontRenderer.drawEmptyTerminal( FixedWidthFontRenderer.drawEmptyTerminal(
transform.last().pose(), renderer, transform, renderer.getBuffer( RenderTypes.MONITOR ),
-MARGIN, MARGIN, -MARGIN, MARGIN,
(float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2) (float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2), FULL_BRIGHT_LIGHTMAP
); );
} }
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 renderer, PoseStack transform, ClientMonitor monitor, float xMargin, float yMargin )
{ {
Terminal terminal = monitor.getTerminal(); Terminal terminal = monitor.getTerminal();
@ -198,15 +194,13 @@ 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() );
Matrix4f matrix = transform.last().pose();
VertexConsumer buffer = renderer.getBuffer( RenderTypes.MONITOR_TBO ); VertexConsumer buffer = renderer.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 );
tboVertex( buffer, matrix, pixelWidth + xMargin, pixelHeight + yMargin ); tboVertex( buffer, matrix, pixelWidth + xMargin, pixelHeight + yMargin );
// And force things to flush. We strictly speaking do this later on anyway for the cursor, but nice to
// be consistent.
renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH );
break; break;
} }
@ -217,19 +211,32 @@ public class TileEntityMonitorRenderer implements BlockEntityRenderer<TileMonito
{ {
Tesselator tessellator = Tesselator.getInstance(); Tesselator tessellator = Tesselator.getInstance();
BufferBuilder builder = tessellator.getBuilder(); BufferBuilder builder = tessellator.getBuilder();
builder.begin( RenderTypes.TERMINAL_WITHOUT_DEPTH.mode(), RenderTypes.TERMINAL_WITHOUT_DEPTH.format() ); builder.begin( RenderTypes.MONITOR.mode(), RenderTypes.MONITOR.format() );
FixedWidthFontRenderer.drawTerminalWithoutCursor( FixedWidthFontRenderer.drawTerminalWithoutCursor(
IDENTITY, builder, 0, 0, new PoseStack(), builder, 0, 0,
terminal, !monitor.isColour(), yMargin, yMargin, xMargin, xMargin terminal, !monitor.isColour(), yMargin, yMargin, xMargin, xMargin, FULL_BRIGHT_LIGHTMAP
); );
builder.end(); builder.end();
vbo.upload( builder ); vbo.upload( builder );
} }
renderer.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ); Matrix3f popViewRotation = RenderSystem.getInverseViewRotationMatrix();
RenderTypes.TERMINAL_WITHOUT_DEPTH.setupRenderState(); RenderSystem.setInverseViewRotationMatrix( IDENTITY );
vbo.drawWithShader( matrix, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader() );
RenderTypes.MONITOR.setupRenderState();
vbo.drawWithShader( transform.last().pose(), RenderSystem.getProjectionMatrix(), RenderTypes.getMonitorShader() );
RenderTypes.MONITOR.clearRenderState();
RenderSystem.setInverseViewRotationMatrix( popViewRotation );
// How we would draw the terminal without using VBO, for reference until I need to delete this.
//VertexConsumer buffer = renderer.getBuffer( RenderTypes.MONITOR );
//FixedWidthFontRenderer.drawTerminalWithoutCursor(
// transform, buffer, 0, 0,
// terminal, !monitor.isColour(), yMargin, yMargin, xMargin, xMargin, FULL_BRIGHT_LIGHTMAP
//);
break; break;
} }
} }

View File

@ -28,11 +28,6 @@ public class MixinGameRenderer
@Inject( method = "reloadShaders", at = @At( value = "INVOKE_ASSIGN", target = "Ljava/util/List;add(Ljava/lang/Object;)Z", ordinal = 53 ), locals = LocalCapture.CAPTURE_FAILSOFT ) @Inject( method = "reloadShaders", at = @At( value = "INVOKE_ASSIGN", target = "Ljava/util/List;add(Ljava/lang/Object;)Z", ordinal = 53 ), locals = LocalCapture.CAPTURE_FAILSOFT )
private void reloadShaders( ResourceManager manager, CallbackInfo info, List<Program> list, List<Pair<ShaderInstance, Consumer<ShaderInstance>>> list2 ) throws IOException private void reloadShaders( ResourceManager manager, CallbackInfo info, List<Program> list, List<Pair<ShaderInstance, Consumer<ShaderInstance>>> list2 ) throws IOException
{ {
list2.add( Pair.of( new ShaderInstance(
manager,
"terminal",
RenderTypes.TERMINAL_WITHOUT_DEPTH.format()
), shader -> RenderTypes.terminalShader = shader ) );
list2.add( Pair.of( new MonitorTextureBufferShader( list2.add( Pair.of( new MonitorTextureBufferShader(
manager, manager,
"monitor_tbo", "monitor_tbo",

View File

@ -7,7 +7,6 @@ package dan200.computercraft.shared.integration;
import com.terraformersmc.modmenu.api.ConfigScreenFactory; import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi; import com.terraformersmc.modmenu.api.ModMenuApi;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
import dan200.computercraft.shared.util.Config; import dan200.computercraft.shared.util.Config;
import me.shedaniel.clothconfig2.api.ConfigBuilder; import me.shedaniel.clothconfig2.api.ConfigBuilder;
@ -33,20 +32,60 @@ public class ModMenuIntegration implements ModMenuApi
Config.clientSpec.correct( Config.clientConfig ); Config.clientSpec.correct( Config.clientConfig );
Config.sync(); Config.sync();
Config.save(); Config.save();
ComputerCraft.log.info( "Monitor renderer: {}", ComputerCraft.monitorRenderer );
} ); } );
ConfigCategory client = builder.getOrCreateCategory( new TextComponent( "Client" ) ); ConfigCategory client = builder.getOrCreateCategory( new TextComponent( "Client" ) );
ConfigEntryBuilder entryBuilder = builder.entryBuilder(); ConfigEntryBuilder entryBuilder = builder.entryBuilder();
client.addEntry( entryBuilder.startEnumSelector( new TextComponent( "Monitor Renderer" ), MonitorRenderer.class, ComputerCraft.monitorRenderer ) client.addEntry( entryBuilder
.startEnumSelector(
new TextComponent( "Monitor Renderer" ),
MonitorRenderer.class,
Config.clientConfig.getEnum( "monitor_renderer", MonitorRenderer.class )
)
.setDefaultValue( MonitorRenderer.BEST ) .setDefaultValue( MonitorRenderer.BEST )
.setSaveConsumer( renderer -> Config.clientConfig.set( "monitor_renderer", renderer ) ) .setSaveConsumer( renderer -> Config.clientConfig.set( "monitor_renderer", renderer ) )
.setTooltip( Component.nullToEmpty( Config.clientConfig.getComment( "monitor_renderer" ) ) ) .setTooltip( Component.nullToEmpty( rewrapComment( Config.clientConfig.getComment( "monitor_renderer" ) ) ) )
.build() ); .build() );
return builder.build(); return builder.build();
}; };
} }
private static String rewrapComment( String comment )
{
String[] words = comment.strip().replaceAll( "[\r\n]", "" ).split( " " );
StringBuilder builder = new StringBuilder();
int lineLength = 0;
for( String word : words )
{
int wordLength = word.length();
if( lineLength + wordLength + 1 > 50 )
{
builder.append( "\n" );
lineLength = 0;
builder.append( word );
lineLength += wordLength;
}
else
{
if( builder.length() == 0 )
{
builder.append( word );
lineLength += wordLength;
}
else
{
builder.append( " " );
builder.append( word );
lineLength += wordLength + 1;
}
}
}
return new String( builder );
}
} }

View File

@ -8,7 +8,6 @@ package dan200.computercraft.shared.peripheral.monitor;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.render.TileEntityMonitorRenderer; import dan200.computercraft.client.render.TileEntityMonitorRenderer;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
import org.lwjgl.opengl.GL;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Arrays; import java.util.Arrays;
@ -49,61 +48,33 @@ public enum MonitorRenderer
@Nonnull @Nonnull
public static MonitorRenderer current() public static MonitorRenderer current()
{ {
MonitorRenderer current = ComputerCraft.monitorRenderer; if( !initialised ) initialise();
switch( current )
{
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; MonitorRenderer current = ComputerCraft.monitorRenderer;
default: if( current == BEST ) return best();
return current; return current;
}
} }
private static MonitorRenderer best() private static MonitorRenderer best()
{ {
if( !initialised ) if( shaderMod )
{ {
checkCapabilities(); ComputerCraft.log.warn( "Shader mod detected. Enabling VBO monitor renderer for compatibility." );
checkForShaderMods(); return ComputerCraft.monitorRenderer = VBO;
if( textureBuffer && shaderMod )
{
ComputerCraft.log.warn( "Shader mod detected. Enabling VBO renderer for compatibility." );
}
initialised = true;
} }
return ComputerCraft.monitorRenderer = TBO;
return textureBuffer && !shaderMod ? TBO : VBO;
} }
private static boolean initialised = false; private static boolean initialised = false;
private static boolean textureBuffer = false; private static boolean shaderMod;
private static boolean shaderMod = false; private static final List<String> shaderModIds = Arrays.asList( "iris", "canvas", "optifabric" );
//TODO find out which shader mods do better with VBOs and add them here.
private static List<String> shaderModIds = Arrays.asList( "optifabric" );
private static void checkCapabilities() private static void initialise()
{
if( initialised ) return;
textureBuffer = GL.getCapabilities().OpenGL31;
initialised = true;
}
private static void checkForShaderMods()
{ {
shaderMod = FabricLoader.getInstance().getAllMods().stream() shaderMod = FabricLoader.getInstance().getAllMods().stream()
.map( modContainer -> modContainer.getMetadata().getId() ) .map( modContainer -> modContainer.getMetadata().getId() )
.anyMatch( id -> shaderModIds.contains( id ) ); .anyMatch( shaderModIds::contains );
initialised = true;
} }
} }