mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-11-01 22:22:59 +00:00
Compare commits
29 Commits
v1.16.5-1.
...
v1.16.5-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f108ba93af | ||
|
|
ad228e94a3 | ||
|
|
fccca22d3f | ||
|
|
4bfdb65989 | ||
|
|
22e8b9b587 | ||
|
|
77a00b14ae | ||
|
|
78aa757549 | ||
|
|
1196568a7c | ||
|
|
48c4f397f9 | ||
|
|
8871f40ced | ||
|
|
aa62c1f206 | ||
|
|
fd32b06d6f | ||
|
|
739d6813c0 | ||
|
|
daf81b897a | ||
|
|
e865d96f7b | ||
|
|
79b1872cab | ||
|
|
2a92794da3 | ||
|
|
b3e009cca5 | ||
|
|
2c64186965 | ||
|
|
31ba17d085 | ||
|
|
bcc7dd6991 | ||
|
|
bd36185662 | ||
|
|
045c4fc88c | ||
|
|
e0fcc425c6 | ||
|
|
e01895d719 | ||
|
|
87b38f4249 | ||
|
|
60d1d1bb18 | ||
|
|
cdf8b77ffd | ||
|
|
e2ce52fe81 |
@@ -19,8 +19,8 @@ numerical value depending on which button on your mouse was last pressed when th
|
||||
<!-- Our markdown parser doesn't work on tables!? Guess I'll have to roll my own soonish :/. -->
|
||||
<tr><th>Button code</th><th>Mouse button</th></tr>
|
||||
<tr><td align="right">1</td><td>Left button</td></tr>
|
||||
<tr><td align="right">2</td><td>Middle button</td></tr>
|
||||
<tr><td align="right">3</td><td>Right button</td></tr>
|
||||
<tr><td align="right">2</td><td>Right button</td></tr>
|
||||
<tr><td align="right">3</td><td>Middle button</td></tr>
|
||||
</table>
|
||||
|
||||
## Example
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Mod properties
|
||||
mod_version=1.100.2
|
||||
mod_version=1.100.5
|
||||
|
||||
# Minecraft properties (update mods.toml when changing)
|
||||
mc_version=1.16.5
|
||||
|
||||
@@ -118,7 +118,7 @@ public final class ComputerCraftAPI
|
||||
}
|
||||
|
||||
/**
|
||||
* rers a peripheral provider to convert blocks into {@link IPeripheral} implementations.
|
||||
* Registers a peripheral provider to convert blocks into {@link IPeripheral} implementations.
|
||||
*
|
||||
* @param provider The peripheral provider to register.
|
||||
* @see IPeripheral
|
||||
|
||||
@@ -10,7 +10,6 @@ import dan200.computercraft.client.gui.*;
|
||||
import dan200.computercraft.client.render.TileEntityMonitorRenderer;
|
||||
import dan200.computercraft.client.render.TileEntityTurtleRenderer;
|
||||
import dan200.computercraft.client.render.TurtleModelLoader;
|
||||
import dan200.computercraft.client.render.TurtlePlayerRenderer;
|
||||
import dan200.computercraft.shared.Registry;
|
||||
import dan200.computercraft.shared.common.IColouredItem;
|
||||
import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
|
||||
@@ -33,7 +32,6 @@ import net.minecraftforge.client.event.ModelRegistryEvent;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.client.model.ModelLoaderRegistry;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.client.registry.RenderingRegistry;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
||||
|
||||
@@ -140,8 +138,6 @@ public final class ClientRegistry
|
||||
net.minecraftforge.fml.client.registry.ClientRegistry.bindTileEntityRenderer( Registry.ModTiles.TURTLE_NORMAL.get(), TileEntityTurtleRenderer::new );
|
||||
net.minecraftforge.fml.client.registry.ClientRegistry.bindTileEntityRenderer( Registry.ModTiles.TURTLE_ADVANCED.get(), TileEntityTurtleRenderer::new );
|
||||
|
||||
RenderingRegistry.registerEntityRenderingHandler( Registry.ModEntities.TURTLE_PLAYER.get(), TurtlePlayerRenderer::new );
|
||||
|
||||
registerItemProperty( "state",
|
||||
( stack, world, player ) -> ItemPocketComputer.getState( stack ).ordinal(),
|
||||
Registry.ModItems.POCKET_COMPUTER_NORMAL, Registry.ModItems.POCKET_COMPUTER_ADVANCED
|
||||
|
||||
@@ -1,349 +0,0 @@
|
||||
/*
|
||||
* 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.gui;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||
import dan200.computercraft.client.FrameInfo;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.core.terminal.TextBuffer;
|
||||
import dan200.computercraft.shared.util.Colour;
|
||||
import dan200.computercraft.shared.util.Palette;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||
import net.minecraft.client.renderer.RenderState;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.vector.Matrix4f;
|
||||
import net.minecraft.util.math.vector.TransformationMatrix;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public final class FixedWidthFontRenderer
|
||||
{
|
||||
private static final Matrix4f IDENTITY = TransformationMatrix.identity().getMatrix();
|
||||
|
||||
private static final ResourceLocation FONT = new ResourceLocation( "computercraft", "textures/gui/term_font.png" );
|
||||
|
||||
public static final int FONT_HEIGHT = 9;
|
||||
public static final int FONT_WIDTH = 6;
|
||||
public static final float WIDTH = 256.0f;
|
||||
|
||||
public static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH;
|
||||
public static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH;
|
||||
|
||||
public static final RenderType TYPE = Type.MAIN;
|
||||
|
||||
private FixedWidthFontRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
public static float toGreyscale( double[] rgb )
|
||||
{
|
||||
return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3);
|
||||
}
|
||||
|
||||
public static int getColour( char c, Colour def )
|
||||
{
|
||||
return 15 - Terminal.getColour( c, def );
|
||||
}
|
||||
|
||||
private static void drawChar( Matrix4f transform, IVertexBuilder buffer, float x, float y, int index, float r, float g, float b )
|
||||
{
|
||||
// Short circuit to avoid the common case - the texture should be blank here after all.
|
||||
if( index == '\0' || index == ' ' ) return;
|
||||
|
||||
int column = index % 16;
|
||||
int row = index / 16;
|
||||
|
||||
int xStart = 1 + column * (FONT_WIDTH + 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 ).endVertex();
|
||||
buffer.vertex( transform, x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).uv( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex();
|
||||
buffer.vertex( transform, x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).uv( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).endVertex();
|
||||
buffer.vertex( transform, x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).uv( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).endVertex();
|
||||
buffer.vertex( transform, x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).uv( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).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 ).endVertex();
|
||||
}
|
||||
|
||||
private static void drawQuad( Matrix4f transform, IVertexBuilder buffer, float x, float y, float width, float height, float r, float g, float b )
|
||||
{
|
||||
buffer.vertex( transform, x, y, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_START, BACKGROUND_START ).endVertex();
|
||||
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, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_START ).endVertex();
|
||||
buffer.vertex( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_START ).endVertex();
|
||||
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, IVertexBuilder buffer, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex )
|
||||
{
|
||||
double[] colour = palette.getColour( getColour( colourIndex, Colour.BLACK ) );
|
||||
float r, g, b;
|
||||
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(
|
||||
@Nonnull Matrix4f transform, @Nonnull IVertexBuilder renderer, float x, float y,
|
||||
@Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale,
|
||||
float leftMarginSize, float rightMarginSize, float height
|
||||
)
|
||||
{
|
||||
if( leftMarginSize > 0 )
|
||||
{
|
||||
drawQuad( transform, renderer, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ) );
|
||||
}
|
||||
|
||||
if( rightMarginSize > 0 )
|
||||
{
|
||||
drawQuad( transform, renderer, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, greyscale, backgroundColour.charAt( backgroundColour.length() - 1 ) );
|
||||
}
|
||||
|
||||
// Batch together runs of identical background cells.
|
||||
int blockStart = 0;
|
||||
char blockColour = '\0';
|
||||
for( int i = 0; i < backgroundColour.length(); i++ )
|
||||
{
|
||||
char colourIndex = backgroundColour.charAt( i );
|
||||
if( colourIndex == blockColour ) continue;
|
||||
|
||||
if( blockColour != '\0' )
|
||||
{
|
||||
drawQuad( transform, renderer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour );
|
||||
}
|
||||
|
||||
blockColour = colourIndex;
|
||||
blockStart = i;
|
||||
}
|
||||
|
||||
if( blockColour != '\0' )
|
||||
{
|
||||
drawQuad( transform, renderer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, greyscale, blockColour );
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawString(
|
||||
@Nonnull Matrix4f transform, @Nonnull IVertexBuilder renderer, float x, float y,
|
||||
@Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour,
|
||||
@Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize
|
||||
)
|
||||
{
|
||||
if( backgroundColour != null )
|
||||
{
|
||||
drawBackground( transform, renderer, x, y, backgroundColour, palette, greyscale, leftMarginSize, rightMarginSize, FONT_HEIGHT );
|
||||
}
|
||||
|
||||
for( int i = 0; i < text.length(); i++ )
|
||||
{
|
||||
double[] colour = palette.getColour( getColour( textColour.charAt( i ), Colour.BLACK ) );
|
||||
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
|
||||
int index = text.charAt( i );
|
||||
if( index > 255 ) index = '?';
|
||||
drawChar( transform, renderer, x + i * FONT_WIDTH, y, index, r, g, b );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void drawString(
|
||||
float x, float y, @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour,
|
||||
@Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize
|
||||
)
|
||||
{
|
||||
bindFont();
|
||||
|
||||
IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().renderBuffers().bufferSource();
|
||||
drawString( IDENTITY, ((IRenderTypeBuffer) renderer).getBuffer( TYPE ), x, y, text, textColour, backgroundColour, palette, greyscale, leftMarginSize, rightMarginSize );
|
||||
renderer.endBatch();
|
||||
}
|
||||
|
||||
public static void drawTerminalWithoutCursor(
|
||||
@Nonnull Matrix4f transform, @Nonnull IVertexBuilder buffer, float x, float y,
|
||||
@Nonnull Terminal terminal, boolean greyscale,
|
||||
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
|
||||
)
|
||||
{
|
||||
Palette palette = terminal.getPalette();
|
||||
int height = terminal.getHeight();
|
||||
|
||||
// Top and bottom margins
|
||||
drawBackground(
|
||||
transform, buffer, x, y - topMarginSize,
|
||||
terminal.getBackgroundColourLine( 0 ), palette, greyscale,
|
||||
leftMarginSize, rightMarginSize, topMarginSize
|
||||
);
|
||||
|
||||
drawBackground(
|
||||
transform, buffer, x, y + height * FONT_HEIGHT,
|
||||
terminal.getBackgroundColourLine( height - 1 ), palette, greyscale,
|
||||
leftMarginSize, rightMarginSize, bottomMarginSize
|
||||
);
|
||||
|
||||
// The main text
|
||||
for( int i = 0; i < height; i++ )
|
||||
{
|
||||
drawString(
|
||||
transform, buffer, x, y + FixedWidthFontRenderer.FONT_HEIGHT * i,
|
||||
terminal.getLine( i ), terminal.getTextColourLine( i ), terminal.getBackgroundColourLine( i ),
|
||||
palette, greyscale, leftMarginSize, rightMarginSize
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawCursor(
|
||||
@Nonnull Matrix4f transform, @Nonnull IVertexBuilder buffer, float x, float y,
|
||||
@Nonnull Terminal terminal, boolean greyscale
|
||||
)
|
||||
{
|
||||
Palette palette = terminal.getPalette();
|
||||
int width = terminal.getWidth();
|
||||
int height = terminal.getHeight();
|
||||
|
||||
int cursorX = terminal.getCursorX();
|
||||
int cursorY = terminal.getCursorY();
|
||||
if( terminal.getCursorBlink() && cursorX >= 0 && cursorX < width && cursorY >= 0 && cursorY < height && FrameInfo.getGlobalCursorBlink() )
|
||||
{
|
||||
double[] colour = palette.getColour( 15 - terminal.getTextColour() );
|
||||
float r, g, b;
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawTerminal(
|
||||
@Nonnull Matrix4f transform, @Nonnull IVertexBuilder buffer, float x, float y,
|
||||
@Nonnull Terminal terminal, boolean greyscale,
|
||||
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
|
||||
)
|
||||
{
|
||||
drawTerminalWithoutCursor( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
|
||||
drawCursor( transform, buffer, x, y, terminal, greyscale );
|
||||
}
|
||||
|
||||
public static void drawTerminal(
|
||||
@Nonnull Matrix4f transform, float x, float y, @Nonnull Terminal terminal, boolean greyscale,
|
||||
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
|
||||
)
|
||||
{
|
||||
bindFont();
|
||||
|
||||
IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().renderBuffers().bufferSource();
|
||||
IVertexBuilder buffer = renderer.getBuffer( TYPE );
|
||||
drawTerminal( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
|
||||
renderer.endBatch( TYPE );
|
||||
}
|
||||
|
||||
public static void drawTerminal(
|
||||
float x, float y, @Nonnull Terminal terminal, boolean greyscale,
|
||||
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
|
||||
)
|
||||
{
|
||||
drawTerminal( IDENTITY, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
|
||||
}
|
||||
|
||||
public static void drawEmptyTerminal( @Nonnull Matrix4f transform, @Nonnull IRenderTypeBuffer renderer, float x, float y, float width, float height )
|
||||
{
|
||||
Colour colour = Colour.BLACK;
|
||||
drawQuad( transform, renderer.getBuffer( TYPE ), 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 )
|
||||
{
|
||||
bindFont();
|
||||
|
||||
IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().renderBuffers().bufferSource();
|
||||
drawEmptyTerminal( transform, renderer, x, y, width, height );
|
||||
renderer.endBatch();
|
||||
}
|
||||
|
||||
public static void drawEmptyTerminal( float x, float y, float width, float height )
|
||||
{
|
||||
drawEmptyTerminal( IDENTITY, x, y, width, height );
|
||||
}
|
||||
|
||||
public static void drawBlocker( @Nonnull Matrix4f transform, @Nonnull IRenderTypeBuffer renderer, float x, float y, float width, float height )
|
||||
{
|
||||
Colour colour = Colour.BLACK;
|
||||
drawQuad( transform, renderer.getBuffer( Type.BLOCKER ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() );
|
||||
}
|
||||
|
||||
private static void bindFont()
|
||||
{
|
||||
Minecraft.getInstance().getTextureManager().bind( FONT );
|
||||
RenderSystem.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP );
|
||||
}
|
||||
|
||||
private static final class Type extends RenderState
|
||||
{
|
||||
private static final int GL_MODE = GL11.GL_TRIANGLES;
|
||||
|
||||
private static final VertexFormat FORMAT = DefaultVertexFormats.POSITION_COLOR_TEX;
|
||||
|
||||
static final RenderType MAIN = RenderType.create(
|
||||
"terminal_font", FORMAT, GL_MODE, 1024,
|
||||
false, false, // useDelegate, needsSorting
|
||||
RenderType.State.builder()
|
||||
.setTextureState( new RenderState.TextureState( FONT, false, false ) ) // blur, minimap
|
||||
.setAlphaState( DEFAULT_ALPHA )
|
||||
.setLightmapState( NO_LIGHTMAP )
|
||||
.setWriteMaskState( COLOR_WRITE )
|
||||
.createCompositeState( false )
|
||||
);
|
||||
|
||||
static final RenderType BLOCKER = RenderType.create(
|
||||
"terminal_blocker", FORMAT, GL_MODE, 256,
|
||||
false, false, // useDelegate, needsSorting
|
||||
RenderType.State.builder()
|
||||
.setTextureState( new RenderState.TextureState( FONT, false, false ) ) // blur, minimap
|
||||
.setAlphaState( DEFAULT_ALPHA )
|
||||
.setWriteMaskState( DEPTH_WRITE )
|
||||
.setLightmapState( NO_LIGHTMAP )
|
||||
.createCompositeState( false )
|
||||
);
|
||||
|
||||
private Type( String name, Runnable setup, Runnable destroy )
|
||||
{
|
||||
super( name, setup, destroy );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
package dan200.computercraft.client.gui;
|
||||
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
|
||||
import dan200.computercraft.client.gui.widgets.WidgetTerminal;
|
||||
@@ -19,6 +18,7 @@ import net.minecraft.util.text.ITextComponent;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER;
|
||||
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
|
||||
|
||||
public final class GuiComputer<T extends ContainerComputerBase> extends ComputerScreenBase<T>
|
||||
{
|
||||
@@ -73,9 +73,10 @@ public final class GuiComputer<T extends ContainerComputerBase> extends Computer
|
||||
public void renderBg( @Nonnull MatrixStack stack, float partialTicks, int mouseX, int mouseY )
|
||||
{
|
||||
// Draw a border around the terminal
|
||||
RenderSystem.color4f( 1, 1, 1, 1 );
|
||||
minecraft.getTextureManager().bind( ComputerBorderRenderer.getTexture( family ) );
|
||||
ComputerBorderRenderer.render( terminal.x, terminal.y, getBlitOffset(), terminal.getWidth(), terminal.getHeight() );
|
||||
ComputerBorderRenderer.render(
|
||||
ComputerBorderRenderer.getTexture( family ), terminal.x, terminal.y, getBlitOffset(),
|
||||
FULL_BRIGHT_LIGHTMAP, terminal.getWidth(), terminal.getHeight()
|
||||
);
|
||||
ComputerSidebar.renderBackground( stack, leftPos, topPos + sidebarYOffset );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import dan200.computercraft.core.terminal.TextBuffer;
|
||||
import dan200.computercraft.shared.common.ContainerHeldItem;
|
||||
import dan200.computercraft.shared.media.items.ItemPrintout;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
|
||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.util.math.vector.Matrix4f;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
@@ -21,6 +21,7 @@ import org.lwjgl.glfw.GLFW;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import static dan200.computercraft.client.render.PrintoutRenderer.*;
|
||||
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
|
||||
|
||||
public class GuiPrintout extends ContainerScreen<ContainerHeldItem>
|
||||
{
|
||||
@@ -97,10 +98,10 @@ public class GuiPrintout extends ContainerScreen<ContainerHeldItem>
|
||||
RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f );
|
||||
RenderSystem.enableDepthTest();
|
||||
|
||||
IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().renderBuffers().bufferSource();
|
||||
IRenderTypeBuffer.Impl renderer = IRenderTypeBuffer.immediate( Tessellator.getInstance().getBuilder() );
|
||||
Matrix4f matrix = transform.last().pose();
|
||||
drawBorder( matrix, renderer, leftPos, topPos, getBlitOffset(), page, pages, book );
|
||||
drawText( matrix, renderer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * page, text, colours );
|
||||
drawBorder( matrix, renderer, leftPos, topPos, getBlitOffset(), page, pages, book, FULL_BRIGHT_LIGHTMAP );
|
||||
drawText( matrix, renderer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * page, FULL_BRIGHT_LIGHTMAP, text, colours );
|
||||
renderer.endBatch();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,22 +6,28 @@
|
||||
package dan200.computercraft.client.gui.widgets;
|
||||
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||
import dan200.computercraft.client.render.RenderTypes;
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.shared.computer.core.ClientComputer;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.widget.Widget;
|
||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.util.SharedConstants;
|
||||
import net.minecraft.util.math.vector.Matrix4f;
|
||||
import net.minecraft.util.text.StringTextComponent;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.BitSet;
|
||||
|
||||
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
|
||||
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH;
|
||||
|
||||
public class WidgetTerminal extends Widget
|
||||
{
|
||||
@@ -314,14 +320,23 @@ public class WidgetTerminal extends Widget
|
||||
if( !visible ) return;
|
||||
Matrix4f matrix = transform.last().pose();
|
||||
Terminal terminal = computer.getTerminal();
|
||||
|
||||
Minecraft.getInstance().getTextureManager().bind( FixedWidthFontRenderer.FONT );
|
||||
RenderSystem.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP );
|
||||
|
||||
IRenderTypeBuffer.Impl renderer = IRenderTypeBuffer.immediate( Tessellator.getInstance().getBuilder() );
|
||||
IVertexBuilder buffer = renderer.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH );
|
||||
|
||||
if( terminal != null )
|
||||
{
|
||||
FixedWidthFontRenderer.drawTerminal( matrix, innerX, innerY, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN );
|
||||
FixedWidthFontRenderer.drawTerminal( matrix, buffer, innerX, innerY, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN );
|
||||
}
|
||||
else
|
||||
{
|
||||
FixedWidthFontRenderer.drawEmptyTerminal( matrix, x, y, width, height );
|
||||
FixedWidthFontRenderer.drawEmptyTerminal( matrix, buffer, x, y, width, height );
|
||||
}
|
||||
|
||||
renderer.endBatch();
|
||||
}
|
||||
|
||||
public static int getWidth( int termWidth )
|
||||
|
||||
@@ -5,16 +5,14 @@
|
||||
*/
|
||||
package dan200.computercraft.client.render;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.vector.Matrix4f;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@@ -59,18 +57,19 @@ public class ComputerBorderRenderer
|
||||
private final IVertexBuilder builder;
|
||||
private final int z;
|
||||
private final float r, g, b;
|
||||
private final int light;
|
||||
|
||||
public ComputerBorderRenderer( Matrix4f transform, IVertexBuilder builder, int z, float r, float g, float b )
|
||||
public ComputerBorderRenderer( Matrix4f transform, IVertexBuilder builder, int z, int light, float r, float g, float b )
|
||||
{
|
||||
this.transform = transform;
|
||||
this.builder = builder;
|
||||
this.z = z;
|
||||
this.light = light;
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
|
||||
@Nonnull
|
||||
public static ResourceLocation getTexture( @Nonnull ComputerFamily family )
|
||||
{
|
||||
@@ -86,31 +85,22 @@ public class ComputerBorderRenderer
|
||||
}
|
||||
}
|
||||
|
||||
public static void render( int x, int y, int z, int width, int height )
|
||||
public static RenderType getRenderType( ResourceLocation location )
|
||||
{
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuilder();
|
||||
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR_TEX );
|
||||
|
||||
render( IDENTITY, buffer, x, y, z, width, height );
|
||||
|
||||
RenderSystem.enableAlphaTest();
|
||||
tessellator.end();
|
||||
// See note in RenderTypes about why we use text rather than anything intuitive.
|
||||
return RenderType.text( location );
|
||||
}
|
||||
|
||||
public static void render( Matrix4f transform, IVertexBuilder buffer, int x, int y, int z, int width, int height )
|
||||
public static void render( ResourceLocation location, int x, int y, int z, int light, int width, int height )
|
||||
{
|
||||
render( transform, buffer, x, y, z, width, height, 1, 1, 1 );
|
||||
IRenderTypeBuffer.Impl source = IRenderTypeBuffer.immediate( Tessellator.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, IVertexBuilder buffer, int x, int y, int z, int width, int height, float r, float g, float b )
|
||||
public static void render( Matrix4f transform, IVertexBuilder buffer, int x, int y, int z, int light, int width, int height, boolean withLight, float r, float g, float b )
|
||||
{
|
||||
render( transform, buffer, x, y, z, width, height, false, r, g, b );
|
||||
}
|
||||
|
||||
public static void render( Matrix4f transform, IVertexBuilder buffer, int x, int y, int z, int width, int height, boolean withLight, float r, float g, float b )
|
||||
{
|
||||
new ComputerBorderRenderer( transform, buffer, z, r, g, b ).doRender( x, y, width, height, withLight );
|
||||
new ComputerBorderRenderer( transform, buffer, z, light, r, g, b ).doRender( x, y, width, height, withLight );
|
||||
}
|
||||
|
||||
public void doRender( int x, int y, int width, int height, boolean withLight )
|
||||
@@ -160,9 +150,9 @@ public class ComputerBorderRenderer
|
||||
|
||||
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 ).endVertex();
|
||||
builder.vertex( transform, x + width, y + height, z ).color( r, g, b, 1.0f ).uv( (u + textureWidth) * TEX_SCALE, (v + textureHeight) * TEX_SCALE ).endVertex();
|
||||
builder.vertex( transform, x + width, y, z ).color( r, g, b, 1.0f ).uv( (u + textureWidth) * TEX_SCALE, v * TEX_SCALE ).endVertex();
|
||||
builder.vertex( transform, x, y, z ).color( r, g, b, 1.0f ).uv( u * TEX_SCALE, v * TEX_SCALE ).endVertex();
|
||||
builder.vertex( transform, x, y + height, z ).color( r, g, b, 1.0f ).uv( u * TEX_SCALE, (v + textureHeight) * TEX_SCALE ).uv2( light ).endVertex();
|
||||
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();
|
||||
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( transform, x, y, z ).color( r, g, b, 1.0f ).uv( u * TEX_SCALE, v * TEX_SCALE ).uv2( light ).endVertex();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,10 @@ public abstract class ItemMapLikeRenderer
|
||||
* @param transform The matrix transformation stack
|
||||
* @param render The buffer to render to
|
||||
* @param stack The stack to render
|
||||
* @param light The packed lightmap coordinates.
|
||||
* @see FirstPersonRenderer#renderItemInFirstPerson(AbstractClientPlayerEntity, float, float, Hand, float, ItemStack, float, MatrixStack, IRenderTypeBuffer, int)
|
||||
*/
|
||||
protected abstract void renderItem( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack );
|
||||
protected abstract void renderItem( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack, int light );
|
||||
|
||||
protected void renderItemFirstPerson( MatrixStack transform, IRenderTypeBuffer render, int lightTexture, Hand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack )
|
||||
{
|
||||
@@ -89,7 +90,7 @@ public abstract class ItemMapLikeRenderer
|
||||
transform.mulPose( Vector3f.XP.rotationDegrees( f2 * -45f ) );
|
||||
transform.mulPose( Vector3f.YP.rotationDegrees( offset * f2 * -30f ) );
|
||||
|
||||
renderItem( transform, render, stack );
|
||||
renderItem( transform, render, stack, combinedLight );
|
||||
|
||||
transform.popPose();
|
||||
}
|
||||
@@ -134,6 +135,6 @@ public abstract class ItemMapLikeRenderer
|
||||
transform.mulPose( Vector3f.XP.rotationDegrees( rX * 20.0F ) );
|
||||
transform.scale( 2.0F, 2.0F, 2.0F );
|
||||
|
||||
renderItem( transform, render, stack );
|
||||
renderItem( transform, render, stack, combinedLight );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,31 +6,27 @@
|
||||
package dan200.computercraft.client.render;
|
||||
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.shared.computer.core.ClientComputer;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
|
||||
import dan200.computercraft.shared.util.Colour;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.vector.Matrix4f;
|
||||
import net.minecraft.util.math.vector.Vector3f;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.RenderHandEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
|
||||
import static dan200.computercraft.client.render.ComputerBorderRenderer.*;
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH;
|
||||
|
||||
/**
|
||||
* Emulates map rendering for pocket computers.
|
||||
@@ -58,7 +54,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderItem( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack )
|
||||
protected void renderItem( MatrixStack transform, IRenderTypeBuffer bufferSource, ItemStack stack, int light )
|
||||
{
|
||||
ClientComputer computer = ItemPocketComputer.createClientComputer( stack );
|
||||
Terminal terminal = computer == null ? null : computer.getTerminal();
|
||||
@@ -95,61 +91,58 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
|
||||
int frameColour = item.getColour( stack );
|
||||
|
||||
Matrix4f matrix = transform.last().pose();
|
||||
renderFrame( matrix, family, frameColour, width, height );
|
||||
renderFrame( matrix, bufferSource, family, frameColour, light, width, height );
|
||||
|
||||
// Render the light
|
||||
int lightColour = ItemPocketComputer.getLightState( stack );
|
||||
if( lightColour == -1 ) lightColour = Colour.BLACK.getHex();
|
||||
renderLight( matrix, lightColour, width, height );
|
||||
renderLight( matrix, bufferSource, lightColour, width, height );
|
||||
|
||||
if( computer != null && terminal != null )
|
||||
{
|
||||
FixedWidthFontRenderer.drawTerminal( matrix, MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN );
|
||||
FixedWidthFontRenderer.drawTerminal(
|
||||
matrix, bufferSource.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ),
|
||||
MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN
|
||||
);
|
||||
FixedWidthFontRenderer.drawBlocker(
|
||||
matrix, bufferSource.getBuffer( RenderTypes.TERMINAL_BLOCKER ),
|
||||
0, 0, width, height
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
FixedWidthFontRenderer.drawEmptyTerminal( matrix, 0, 0, width, height );
|
||||
FixedWidthFontRenderer.drawEmptyTerminal(
|
||||
matrix, bufferSource.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH ),
|
||||
0, 0, width, height
|
||||
);
|
||||
}
|
||||
|
||||
transform.popPose();
|
||||
}
|
||||
|
||||
private static void renderFrame( Matrix4f transform, ComputerFamily family, int colour, int width, int height )
|
||||
private static void renderFrame( Matrix4f transform, IRenderTypeBuffer bufferSource, ComputerFamily family, int colour, int light, int width, int height )
|
||||
{
|
||||
RenderSystem.enableBlend();
|
||||
Minecraft.getInstance().getTextureManager()
|
||||
.bind( colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family ) );
|
||||
ResourceLocation texture = colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family );
|
||||
|
||||
float r = ((colour >>> 16) & 0xFF) / 255.0f;
|
||||
float g = ((colour >>> 8) & 0xFF) / 255.0f;
|
||||
float b = (colour & 0xFF) / 255.0f;
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuilder();
|
||||
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR_TEX );
|
||||
|
||||
ComputerBorderRenderer.render( transform, buffer, 0, 0, 0, width, height, true, r, g, b );
|
||||
|
||||
tessellator.end();
|
||||
ComputerBorderRenderer.render( transform, bufferSource.getBuffer( ComputerBorderRenderer.getRenderType( texture ) ), 0, 0, 0, light, width, height, true, r, g, b );
|
||||
}
|
||||
|
||||
private static void renderLight( Matrix4f transform, int colour, int width, int height )
|
||||
private static void renderLight( Matrix4f transform, IRenderTypeBuffer bufferSource, int colour, int width, int height )
|
||||
{
|
||||
RenderSystem.disableTexture();
|
||||
byte r = (byte) ((colour >>> 16) & 0xFF);
|
||||
byte g = (byte) ((colour >>> 8) & 0xFF);
|
||||
byte b = (byte) (colour & 0xFF);
|
||||
byte[] c = new byte[] { r, g, b, (byte) 255 };
|
||||
|
||||
float r = ((colour >>> 16) & 0xFF) / 255.0f;
|
||||
float g = ((colour >>> 8) & 0xFF) / 255.0f;
|
||||
float b = (colour & 0xFF) / 255.0f;
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuilder();
|
||||
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR );
|
||||
buffer.vertex( transform, width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + BORDER / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex();
|
||||
buffer.vertex( transform, width, height + LIGHT_HEIGHT + BORDER / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex();
|
||||
buffer.vertex( transform, width, height + BORDER / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex();
|
||||
buffer.vertex( transform, width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex();
|
||||
|
||||
tessellator.end();
|
||||
RenderSystem.enableTexture();
|
||||
IVertexBuilder buffer = bufferSource.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH );
|
||||
FixedWidthFontRenderer.drawQuad(
|
||||
transform, buffer,
|
||||
width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, 0.001f, LIGHT_HEIGHT * 2, LIGHT_HEIGHT,
|
||||
c, RenderTypes.FULL_BRIGHT_LIGHTMAP
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ import net.minecraftforge.client.event.RenderItemInFrameEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
|
||||
import static dan200.computercraft.client.render.PrintoutRenderer.*;
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH;
|
||||
import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE;
|
||||
import static dan200.computercraft.shared.media.items.ItemPrintout.LINE_MAX_LENGTH;
|
||||
|
||||
@@ -50,13 +50,13 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderItem( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack )
|
||||
protected void renderItem( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack, int light )
|
||||
{
|
||||
transform.mulPose( Vector3f.XP.rotationDegrees( 180f ) );
|
||||
transform.scale( 0.42f, 0.42f, -0.42f );
|
||||
transform.translate( -0.5f, -0.48f, 0.0f );
|
||||
|
||||
drawPrintout( transform, render, stack );
|
||||
drawPrintout( transform, render, stack, light );
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@@ -74,10 +74,10 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
|
||||
transform.scale( 0.95f, 0.95f, -0.95f );
|
||||
transform.translate( -0.5f, -0.5f, 0.0f );
|
||||
|
||||
drawPrintout( transform, event.getBuffers(), stack );
|
||||
drawPrintout( transform, event.getBuffers(), stack, event.getLight() );
|
||||
}
|
||||
|
||||
private static void drawPrintout( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack )
|
||||
private static void drawPrintout( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack, int light )
|
||||
{
|
||||
int pages = ItemPrintout.getPageCount( stack );
|
||||
boolean book = ((ItemPrintout) stack.getItem()).getType() == ItemPrintout.Type.BOOK;
|
||||
@@ -105,9 +105,10 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
|
||||
transform.translate( (max - width) / 2.0, (max - height) / 2.0, 0.0 );
|
||||
|
||||
Matrix4f matrix = transform.last().pose();
|
||||
drawBorder( matrix, render, 0, 0, -0.01f, 0, pages, book );
|
||||
drawText( matrix, render,
|
||||
X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack )
|
||||
drawBorder( matrix, render, 0, 0, -0.01f, 0, pages, book, light );
|
||||
drawText(
|
||||
matrix, render, X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, light,
|
||||
ItemPrintout.getText( stack ), ItemPrintout.getColours( stack )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,62 +9,55 @@ import com.google.common.base.Strings;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.client.FrameInfo;
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.core.terminal.TextBuffer;
|
||||
import dan200.computercraft.shared.util.Colour;
|
||||
import dan200.computercraft.shared.util.Palette;
|
||||
import net.minecraft.client.renderer.texture.TextureUtil;
|
||||
import net.minecraft.util.math.vector.Matrix4f;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL31;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.getColour;
|
||||
|
||||
class MonitorTextureBufferShader
|
||||
{
|
||||
public static final int UNIFORM_SIZE = 4 * 4 * 16 + 4 + 4 + 2 * 4 + 4;
|
||||
|
||||
static final int TEXTURE_INDEX = GL13.GL_TEXTURE3;
|
||||
|
||||
private static final FloatBuffer MATRIX_BUFFER = BufferUtils.createFloatBuffer( 16 );
|
||||
private static final FloatBuffer PALETTE_BUFFER = BufferUtils.createFloatBuffer( 16 * 3 );
|
||||
|
||||
private static int uniformMv;
|
||||
|
||||
private static int uniformFont;
|
||||
private static int uniformWidth;
|
||||
private static int uniformHeight;
|
||||
private static int uniformTbo;
|
||||
private static int uniformPalette;
|
||||
private static int uniformMonitor;
|
||||
private static int uniformCursorBlink;
|
||||
|
||||
private static boolean initialised;
|
||||
private static boolean ok;
|
||||
private static int program;
|
||||
|
||||
static void setupUniform( Matrix4f transform, int width, int height, Palette palette, boolean greyscale )
|
||||
static void setupUniform( Matrix4f transform, int tboUniform )
|
||||
{
|
||||
MATRIX_BUFFER.rewind();
|
||||
transform.store( MATRIX_BUFFER );
|
||||
MATRIX_BUFFER.rewind();
|
||||
RenderSystem.glUniformMatrix4( uniformMv, false, MATRIX_BUFFER );
|
||||
|
||||
RenderSystem.glUniform1i( uniformWidth, width );
|
||||
RenderSystem.glUniform1i( uniformHeight, height );
|
||||
GL31.glBindBufferBase( GL31.GL_UNIFORM_BUFFER, uniformMonitor, tboUniform );
|
||||
|
||||
PALETTE_BUFFER.rewind();
|
||||
for( int i = 0; i < 16; i++ )
|
||||
{
|
||||
double[] colour = palette.getColour( i );
|
||||
if( greyscale )
|
||||
{
|
||||
float f = FixedWidthFontRenderer.toGreyscale( colour );
|
||||
PALETTE_BUFFER.put( f ).put( f ).put( f );
|
||||
}
|
||||
else
|
||||
{
|
||||
PALETTE_BUFFER.put( (float) colour[0] ).put( (float) colour[1] ).put( (float) colour[2] );
|
||||
}
|
||||
}
|
||||
PALETTE_BUFFER.flip();
|
||||
RenderSystem.glUniform3( uniformPalette, PALETTE_BUFFER );
|
||||
int cursorAlpha = FrameInfo.getGlobalCursorBlink() ? 1 : 0;
|
||||
RenderSystem.glUniform1i( uniformCursorBlink, cursorAlpha );
|
||||
}
|
||||
|
||||
static boolean use()
|
||||
@@ -116,10 +109,10 @@ class MonitorTextureBufferShader
|
||||
|
||||
uniformMv = getUniformLocation( program, "u_mv" );
|
||||
uniformFont = getUniformLocation( program, "u_font" );
|
||||
uniformWidth = getUniformLocation( program, "u_width" );
|
||||
uniformHeight = getUniformLocation( program, "u_height" );
|
||||
uniformTbo = getUniformLocation( program, "u_tbo" );
|
||||
uniformPalette = getUniformLocation( program, "u_palette" );
|
||||
uniformMonitor = GL31.glGetUniformBlockIndex( program, "u_monitor" );
|
||||
if( uniformMonitor == -1 ) throw new IllegalStateException( "Could not find uniformMonitor uniform." );
|
||||
uniformCursorBlink = getUniformLocation( program, "u_cursorBlink" );
|
||||
|
||||
ComputerCraft.log.info( "Loaded monitor shader." );
|
||||
return true;
|
||||
@@ -159,4 +152,54 @@ class MonitorTextureBufferShader
|
||||
if( uniform == -1 ) throw new IllegalStateException( "Cannot find uniform " + name );
|
||||
return uniform;
|
||||
}
|
||||
|
||||
public static void setTerminalData( ByteBuffer buffer, Terminal terminal )
|
||||
{
|
||||
int width = terminal.getWidth(), height = terminal.getHeight();
|
||||
|
||||
int pos = 0;
|
||||
for( int y = 0; y < height; y++ )
|
||||
{
|
||||
TextBuffer text = terminal.getLine( y ), textColour = terminal.getTextColourLine( y ), background = terminal.getBackgroundColourLine( y );
|
||||
for( int x = 0; x < width; x++ )
|
||||
{
|
||||
buffer.put( pos, (byte) (text.charAt( x ) & 0xFF) );
|
||||
buffer.put( pos + 1, (byte) getColour( textColour.charAt( x ), Colour.WHITE ) );
|
||||
buffer.put( pos + 2, (byte) getColour( background.charAt( x ), Colour.BLACK ) );
|
||||
pos += 3;
|
||||
}
|
||||
}
|
||||
|
||||
buffer.limit( pos );
|
||||
}
|
||||
|
||||
public static void setUniformData( ByteBuffer buffer, Terminal terminal, boolean greyscale )
|
||||
{
|
||||
int pos = 0;
|
||||
Palette palette = terminal.getPalette();
|
||||
for( int i = 0; i < 16; i++ )
|
||||
{
|
||||
double[] colour = palette.getColour( i );
|
||||
if( greyscale )
|
||||
{
|
||||
float f = FixedWidthFontRenderer.toGreyscale( colour );
|
||||
buffer.putFloat( pos, f ).putFloat( pos + 4, f ).putFloat( pos + 8, f );
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.putFloat( pos, (float) colour[0] ).putFloat( pos + 4, (float) colour[1] ).putFloat( pos + 8, (float) colour[2] );
|
||||
}
|
||||
|
||||
pos += 4 * 4; // std140 requires these are 4-wide
|
||||
}
|
||||
|
||||
boolean showCursor = FixedWidthFontRenderer.isCursorVisible( terminal );
|
||||
buffer
|
||||
.putInt( pos, terminal.getWidth() ).putInt( pos + 4, terminal.getHeight() )
|
||||
.putInt( pos + 8, showCursor ? terminal.getCursorX() : -2 )
|
||||
.putInt( pos + 12, showCursor ? terminal.getCursorY() : -2 )
|
||||
.putInt( pos + 16, 15 - terminal.getTextColour() );
|
||||
|
||||
buffer.limit( UNIFORM_SIZE );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,18 +6,14 @@
|
||||
package dan200.computercraft.client.render;
|
||||
|
||||
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.core.terminal.TextBuffer;
|
||||
import dan200.computercraft.shared.util.Palette;
|
||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||
import net.minecraft.client.renderer.RenderState;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.vector.Matrix4f;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||
import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE;
|
||||
|
||||
public final class PrintoutRenderer
|
||||
@@ -60,37 +56,37 @@ public final class PrintoutRenderer
|
||||
|
||||
private PrintoutRenderer() {}
|
||||
|
||||
public static void drawText( Matrix4f transform, IRenderTypeBuffer renderer, int x, int y, int start, TextBuffer[] text, TextBuffer[] colours )
|
||||
public static void drawText( Matrix4f transform, IRenderTypeBuffer renderer, int x, int y, int start, int light, TextBuffer[] text, TextBuffer[] colours )
|
||||
{
|
||||
IVertexBuilder buffer = renderer.getBuffer( FixedWidthFontRenderer.TYPE );
|
||||
IVertexBuilder buffer = renderer.getBuffer( RenderTypes.PRINTOUT_TEXT );
|
||||
for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ )
|
||||
{
|
||||
FixedWidthFontRenderer.drawString( transform, buffer,
|
||||
x, y + line * FONT_HEIGHT, text[start + line], colours[start + line], null, Palette.DEFAULT,
|
||||
false, 0, 0
|
||||
x, y + line * FONT_HEIGHT, text[start + line], colours[start + line],
|
||||
Palette.DEFAULT, false, light
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawText( Matrix4f transform, IRenderTypeBuffer renderer, int x, int y, int start, String[] text, String[] colours )
|
||||
public static void drawText( Matrix4f transform, IRenderTypeBuffer renderer, int x, int y, int start, int light, String[] text, String[] colours )
|
||||
{
|
||||
IVertexBuilder buffer = renderer.getBuffer( FixedWidthFontRenderer.TYPE );
|
||||
IVertexBuilder buffer = renderer.getBuffer( RenderTypes.PRINTOUT_TEXT );
|
||||
for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ )
|
||||
{
|
||||
FixedWidthFontRenderer.drawString( transform, buffer,
|
||||
x, y + line * FONT_HEIGHT,
|
||||
new TextBuffer( text[start + line] ), new TextBuffer( colours[start + line] ),
|
||||
null, Palette.DEFAULT, false, 0, 0
|
||||
Palette.DEFAULT, false, light
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawBorder( Matrix4f transform, IRenderTypeBuffer renderer, float x, float y, float z, int page, int pages, boolean isBook )
|
||||
public static void drawBorder( Matrix4f transform, IRenderTypeBuffer renderer, float x, float y, float z, int page, int pages, boolean isBook, int light )
|
||||
{
|
||||
int leftPages = page;
|
||||
int rightPages = pages - page - 1;
|
||||
|
||||
IVertexBuilder buffer = renderer.getBuffer( Type.TYPE );
|
||||
IVertexBuilder buffer = renderer.getBuffer( RenderTypes.PRINTOUT_BACKGROUND );
|
||||
|
||||
if( isBook )
|
||||
{
|
||||
@@ -100,86 +96,73 @@ public final class PrintoutRenderer
|
||||
float right = x + X_SIZE + offset - 4;
|
||||
|
||||
// Left and right border
|
||||
drawTexture( transform, buffer, left - 4, y - 8, z - 0.02f, COVER_X, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 );
|
||||
drawTexture( transform, buffer, right, y - 8, z - 0.02f, COVER_X + COVER_SIZE, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 );
|
||||
drawTexture( transform, buffer, left - 4, y - 8, z - 0.02f, COVER_X, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2, light );
|
||||
drawTexture( transform, buffer, right, y - 8, z - 0.02f, COVER_X + COVER_SIZE, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2, light );
|
||||
|
||||
// Draw centre panel (just stretched texture, sorry).
|
||||
drawTexture( transform, buffer,
|
||||
x - offset, y, z - 0.02f, X_SIZE + offset * 2, Y_SIZE,
|
||||
COVER_X + COVER_SIZE / 2.0f, COVER_SIZE, COVER_SIZE, Y_SIZE
|
||||
COVER_X + COVER_SIZE / 2.0f, COVER_SIZE, COVER_SIZE, Y_SIZE, light
|
||||
);
|
||||
|
||||
float borderX = left;
|
||||
while( borderX < right )
|
||||
{
|
||||
double thisWidth = Math.min( right - borderX, X_SIZE );
|
||||
drawTexture( transform, buffer, borderX, y - 8, z - 0.02f, 0, COVER_Y, (float) thisWidth, COVER_SIZE );
|
||||
drawTexture( transform, buffer, borderX, y + Y_SIZE - 4, z - 0.02f, 0, COVER_Y + COVER_SIZE, (float) thisWidth, COVER_SIZE );
|
||||
drawTexture( transform, buffer, borderX, y - 8, z - 0.02f, 0, COVER_Y, (float) thisWidth, COVER_SIZE, light );
|
||||
drawTexture( transform, buffer, borderX, y + Y_SIZE - 4, z - 0.02f, 0, COVER_Y + COVER_SIZE, (float) thisWidth, COVER_SIZE, light );
|
||||
borderX += thisWidth;
|
||||
}
|
||||
}
|
||||
|
||||
// Left half
|
||||
drawTexture( transform, buffer, x, y, z, X_FOLD_SIZE * 2, 0, X_SIZE / 2.0f, Y_SIZE );
|
||||
drawTexture( transform, buffer, x, y, z, X_FOLD_SIZE * 2, 0, X_SIZE / 2.0f, Y_SIZE, light );
|
||||
for( int n = 0; n <= leftPages; n++ )
|
||||
{
|
||||
drawTexture( transform, buffer,
|
||||
x - offsetAt( n ), y, z - 1e-3f * n,
|
||||
// Use the left "bold" fold for the outermost page
|
||||
n == leftPages ? 0 : X_FOLD_SIZE, 0,
|
||||
X_FOLD_SIZE, Y_SIZE
|
||||
X_FOLD_SIZE, Y_SIZE, light
|
||||
);
|
||||
}
|
||||
|
||||
// Right half
|
||||
drawTexture( transform, buffer, x + X_SIZE / 2.0f, y, z, X_FOLD_SIZE * 2 + X_SIZE / 2.0f, 0, X_SIZE / 2.0f, Y_SIZE );
|
||||
drawTexture( transform, buffer, x + X_SIZE / 2.0f, y, z, X_FOLD_SIZE * 2 + X_SIZE / 2.0f, 0, X_SIZE / 2.0f, Y_SIZE, light );
|
||||
for( int n = 0; n <= rightPages; n++ )
|
||||
{
|
||||
drawTexture( transform, buffer,
|
||||
x + (X_SIZE - X_FOLD_SIZE) + offsetAt( n ), y, z - 1e-3f * n,
|
||||
// Two folds, then the main page. Use the right "bold" fold for the outermost page.
|
||||
X_FOLD_SIZE * 2 + X_SIZE + (n == rightPages ? X_FOLD_SIZE : 0), 0,
|
||||
X_FOLD_SIZE, Y_SIZE
|
||||
X_FOLD_SIZE, Y_SIZE, light
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawTexture( Matrix4f matrix, IVertexBuilder buffer, float x, float y, float z, float u, float v, float width, float height )
|
||||
private static void drawTexture( Matrix4f matrix, IVertexBuilder buffer, float x, float y, float z, float u, float v, float width, float height, int light )
|
||||
{
|
||||
buffer.vertex( matrix, x, y + height, z ).uv( u / BG_SIZE, (v + height) / BG_SIZE ).endVertex();
|
||||
buffer.vertex( matrix, x + width, y + height, z ).uv( (u + width) / BG_SIZE, (v + height) / BG_SIZE ).endVertex();
|
||||
buffer.vertex( matrix, x + width, y, z ).uv( (u + width) / BG_SIZE, v / BG_SIZE ).endVertex();
|
||||
buffer.vertex( matrix, x, y, z ).uv( u / BG_SIZE, v / BG_SIZE ).endVertex();
|
||||
vertex( buffer, matrix, x, y + height, z, u / BG_SIZE, (v + height) / BG_SIZE, light );
|
||||
vertex( buffer, matrix, x + width, y + height, z, (u + width) / BG_SIZE, (v + height) / BG_SIZE, light );
|
||||
vertex( buffer, matrix, x + width, y, z, (u + width) / BG_SIZE, v / BG_SIZE, light );
|
||||
vertex( buffer, matrix, x, y, z, u / BG_SIZE, v / BG_SIZE, light );
|
||||
}
|
||||
|
||||
private static void drawTexture( Matrix4f matrix, IVertexBuilder buffer, float x, float y, float z, float width, float height, float u, float v, float tWidth, float tHeight )
|
||||
private static void drawTexture( Matrix4f matrix, IVertexBuilder buffer, float x, float y, float z, float width, float height, float u, float v, float tWidth, float tHeight, int light )
|
||||
{
|
||||
buffer.vertex( matrix, x, y + height, z ).uv( u / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex();
|
||||
buffer.vertex( matrix, x + width, y + height, z ).uv( (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex();
|
||||
buffer.vertex( matrix, x + width, y, z ).uv( (u + tWidth) / BG_SIZE, v / BG_SIZE ).endVertex();
|
||||
buffer.vertex( matrix, x, y, z ).uv( u / BG_SIZE, v / BG_SIZE ).endVertex();
|
||||
vertex( buffer, matrix, x, y + height, z, u / BG_SIZE, (v + tHeight) / BG_SIZE, light );
|
||||
vertex( buffer, matrix, x + width, y + height, z, (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE, light );
|
||||
vertex( buffer, matrix, x + width, y, z, (u + tWidth) / BG_SIZE, v / BG_SIZE, light );
|
||||
vertex( buffer, matrix, x, y, z, u / BG_SIZE, v / BG_SIZE, light );
|
||||
}
|
||||
|
||||
private static void vertex( IVertexBuilder buffer, Matrix4f matrix, 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();
|
||||
}
|
||||
|
||||
public static float offsetAt( int page )
|
||||
{
|
||||
return (float) (32 * (1 - Math.pow( 1.2, -page )));
|
||||
}
|
||||
|
||||
private static final class Type extends RenderState
|
||||
{
|
||||
static final RenderType TYPE = RenderType.create(
|
||||
"printout_background", DefaultVertexFormats.POSITION_TEX, GL11.GL_QUADS, 1024,
|
||||
false, false, // useDelegate, needsSorting
|
||||
RenderType.State.builder()
|
||||
.setTextureState( new RenderState.TextureState( BG, false, false ) ) // blur, minimap
|
||||
.setAlphaState( DEFAULT_ALPHA )
|
||||
.setLightmapState( NO_LIGHTMAP )
|
||||
.createCompositeState( false )
|
||||
);
|
||||
|
||||
private Type( String name, Runnable setup, Runnable destroy )
|
||||
{
|
||||
super( name, setup, destroy );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.render;
|
||||
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import net.minecraft.client.renderer.RenderState;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class RenderTypes
|
||||
{
|
||||
public static final int FULL_BRIGHT_LIGHTMAP = (0xF << 4) | (0xF << 20);
|
||||
|
||||
/**
|
||||
* Renders a fullbright terminal without writing to the depth layer. This is used in combination with
|
||||
* {@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.
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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" ) );
|
||||
|
||||
private static final class Types extends RenderState
|
||||
{
|
||||
private static final RenderState.TextureState TERM_FONT_TEXTURE = new RenderState.TextureState(
|
||||
FixedWidthFontRenderer.FONT,
|
||||
false, false // blur, minimap
|
||||
);
|
||||
private static final VertexFormat TERM_FORMAT = DefaultVertexFormats.POSITION_COLOR_TEX;
|
||||
|
||||
static final RenderType TERMINAL_WITHOUT_DEPTH = RenderType.create(
|
||||
"terminal_without_depth", TERM_FORMAT, GL11.GL_QUADS, 1024,
|
||||
false, false, // useDelegate, needsSorting
|
||||
RenderType.State.builder()
|
||||
.setTextureState( TERM_FONT_TEXTURE )
|
||||
.setAlphaState( DEFAULT_ALPHA )
|
||||
.setWriteMaskState( COLOR_WRITE )
|
||||
.createCompositeState( false )
|
||||
);
|
||||
|
||||
static final RenderType TERMINAL_BLOCKER = RenderType.create(
|
||||
"terminal_blocker", DefaultVertexFormats.POSITION, GL11.GL_QUADS, 256,
|
||||
false, false, // useDelegate, needsSorting
|
||||
RenderType.State.builder()
|
||||
.setWriteMaskState( DEPTH_WRITE )
|
||||
.createCompositeState( false )
|
||||
);
|
||||
|
||||
static final RenderType TERMINAL_WITH_DEPTH = RenderType.create(
|
||||
"terminal_with_depth", TERM_FORMAT, GL11.GL_QUADS, 1024,
|
||||
false, false, // useDelegate, needsSorting
|
||||
RenderType.State.builder()
|
||||
.setTextureState( TERM_FONT_TEXTURE )
|
||||
.setAlphaState( DEFAULT_ALPHA )
|
||||
.createCompositeState( false )
|
||||
);
|
||||
|
||||
private Types( String name, Runnable setup, Runnable destroy )
|
||||
{
|
||||
super( name, setup, destroy );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,25 +7,26 @@ package dan200.computercraft.client.render;
|
||||
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||
import dan200.computercraft.client.FrameInfo;
|
||||
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer;
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.client.util.DirectBuffers;
|
||||
import dan200.computercraft.client.util.DirectVertexBuffer;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.core.terminal.TextBuffer;
|
||||
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
||||
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
|
||||
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
|
||||
import dan200.computercraft.shared.util.Colour;
|
||||
import dan200.computercraft.shared.util.DirectionUtil;
|
||||
import net.minecraft.client.renderer.*;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.client.renderer.vertex.VertexBuffer;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.vector.Matrix4f;
|
||||
import net.minecraft.util.math.vector.TransformationMatrix;
|
||||
import net.minecraft.util.math.vector.Vector3f;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
@@ -35,7 +36,8 @@ import org.lwjgl.opengl.GL31;
|
||||
import javax.annotation.Nonnull;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*;
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH;
|
||||
|
||||
public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor>
|
||||
{
|
||||
@@ -44,9 +46,7 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor>
|
||||
* the monitor frame and contents.
|
||||
*/
|
||||
private static final float MARGIN = (float) (TileMonitor.RENDER_MARGIN * 1.1);
|
||||
private static ByteBuffer tboContents;
|
||||
|
||||
private static final Matrix4f IDENTITY = TransformationMatrix.identity().getMatrix();
|
||||
private static ByteBuffer backingBuffer;
|
||||
|
||||
public TileEntityMonitorRenderer( TileEntityRendererDispatcher rendererDispatcher )
|
||||
{
|
||||
@@ -114,46 +114,31 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor>
|
||||
transform.scale( (float) xScale, (float) -yScale, 1.0f );
|
||||
|
||||
Matrix4f matrix = transform.last().pose();
|
||||
renderTerminal( renderer, matrix, originTerminal, (float) (MARGIN / xScale), (float) (MARGIN / yScale) );
|
||||
|
||||
// Sneaky hack here: we get a buffer now in order to flush existing ones and set up the appropriate
|
||||
// render state. I've no clue how well this'll work in future versions of Minecraft, but it does the trick
|
||||
// for now.
|
||||
IVertexBuilder buffer = renderer.getBuffer( FixedWidthFontRenderer.TYPE );
|
||||
FixedWidthFontRenderer.TYPE.setupRenderState();
|
||||
|
||||
renderTerminal( 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
|
||||
// reasonable.
|
||||
FixedWidthFontRenderer.drawCursor( matrix, buffer, 0, 0, terminal, !originTerminal.isColour() );
|
||||
// Force a flush of the buffer. 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() );
|
||||
|
||||
transform.popPose();
|
||||
}
|
||||
else
|
||||
{
|
||||
FixedWidthFontRenderer.drawEmptyTerminal(
|
||||
transform.last().pose(), renderer,
|
||||
transform.last().pose(), renderer.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH ),
|
||||
-MARGIN, MARGIN,
|
||||
(float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)
|
||||
);
|
||||
}
|
||||
|
||||
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() );
|
||||
|
||||
transform.popPose();
|
||||
}
|
||||
|
||||
private static void renderTerminal( Matrix4f matrix, ClientMonitor monitor, float xMargin, float yMargin )
|
||||
private static void renderTerminal( IRenderTypeBuffer bufferSource, Matrix4f matrix, ClientMonitor monitor, float xMargin, float yMargin )
|
||||
{
|
||||
Terminal terminal = monitor.getTerminal();
|
||||
int width = terminal.getWidth(), height = terminal.getHeight();
|
||||
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
|
||||
|
||||
MonitorRenderer renderType = MonitorRenderer.current();
|
||||
boolean redraw = monitor.pollTerminalChanged();
|
||||
@@ -165,42 +150,29 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor>
|
||||
{
|
||||
if( !MonitorTextureBufferShader.use() ) return;
|
||||
|
||||
int width = terminal.getWidth(), height = terminal.getHeight();
|
||||
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
|
||||
|
||||
if( redraw )
|
||||
{
|
||||
int size = width * height * 3;
|
||||
if( tboContents == null || tboContents.capacity() < size )
|
||||
{
|
||||
tboContents = GLAllocation.createByteBuffer( size );
|
||||
}
|
||||
ByteBuffer terminalBuffer = getBuffer( width * height * 3 );
|
||||
MonitorTextureBufferShader.setTerminalData( terminalBuffer, terminal );
|
||||
DirectBuffers.setBufferData( GL31.GL_TEXTURE_BUFFER, monitor.tboBuffer, terminalBuffer, GL20.GL_STATIC_DRAW );
|
||||
|
||||
ByteBuffer monitorBuffer = tboContents;
|
||||
monitorBuffer.clear();
|
||||
for( int y = 0; y < height; y++ )
|
||||
{
|
||||
TextBuffer text = terminal.getLine( y ), textColour = terminal.getTextColourLine( y ), background = terminal.getBackgroundColourLine( y );
|
||||
for( int x = 0; x < width; x++ )
|
||||
{
|
||||
monitorBuffer.put( (byte) (text.charAt( x ) & 0xFF) );
|
||||
monitorBuffer.put( (byte) getColour( textColour.charAt( x ), Colour.WHITE ) );
|
||||
monitorBuffer.put( (byte) getColour( background.charAt( x ), Colour.BLACK ) );
|
||||
}
|
||||
}
|
||||
monitorBuffer.flip();
|
||||
|
||||
GlStateManager._glBindBuffer( GL31.GL_TEXTURE_BUFFER, monitor.tboBuffer );
|
||||
GlStateManager._glBufferData( GL31.GL_TEXTURE_BUFFER, monitorBuffer, GL20.GL_STATIC_DRAW );
|
||||
GlStateManager._glBindBuffer( GL31.GL_TEXTURE_BUFFER, 0 );
|
||||
ByteBuffer uniformBuffer = getBuffer( MonitorTextureBufferShader.UNIFORM_SIZE );
|
||||
MonitorTextureBufferShader.setUniformData( uniformBuffer, terminal, !monitor.isColour() );
|
||||
DirectBuffers.setBufferData( GL31.GL_UNIFORM_BUFFER, monitor.tboUniform, uniformBuffer, GL20.GL_STATIC_DRAW );
|
||||
}
|
||||
|
||||
// Sneaky hack here: we get a buffer now in order to flush existing ones and set up the appropriate
|
||||
// render state. I've no clue how well this'll work in future versions of Minecraft, but it does the trick
|
||||
// for now.
|
||||
bufferSource.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH );
|
||||
RenderTypes.TERMINAL_WITH_DEPTH.setupRenderState();
|
||||
|
||||
// Nobody knows what they're doing!
|
||||
GlStateManager._activeTexture( MonitorTextureBufferShader.TEXTURE_INDEX );
|
||||
GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, monitor.tboTexture );
|
||||
GlStateManager._activeTexture( GL13.GL_TEXTURE0 );
|
||||
|
||||
MonitorTextureBufferShader.setupUniform( matrix, width, height, terminal.getPalette(), !monitor.isColour() );
|
||||
MonitorTextureBufferShader.setupUniform( matrix, monitor.tboUniform );
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuilder();
|
||||
@@ -217,28 +189,59 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer<TileMonitor>
|
||||
|
||||
case VBO:
|
||||
{
|
||||
VertexBuffer vbo = monitor.buffer;
|
||||
DirectVertexBuffer vbo = monitor.buffer;
|
||||
if( redraw )
|
||||
{
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder builder = tessellator.getBuilder();
|
||||
builder.begin( FixedWidthFontRenderer.TYPE.mode(), FixedWidthFontRenderer.TYPE.format() );
|
||||
FixedWidthFontRenderer.drawTerminalWithoutCursor(
|
||||
IDENTITY, builder, 0, 0,
|
||||
terminal, !monitor.isColour(), yMargin, yMargin, xMargin, xMargin
|
||||
);
|
||||
int vertexSize = RenderTypes.TERMINAL_WITHOUT_DEPTH.format().getVertexSize();
|
||||
ByteBuffer buffer = getBuffer( DirectFixedWidthFontRenderer.getVertexCount( terminal ) * vertexSize );
|
||||
|
||||
builder.end();
|
||||
vbo.upload( builder );
|
||||
// Draw the main terminal and store how many vertices it has.
|
||||
DirectFixedWidthFontRenderer.drawTerminalWithoutCursor(
|
||||
buffer, 0, 0, terminal, !monitor.isColour(), yMargin, yMargin, xMargin, xMargin
|
||||
);
|
||||
int termIndexes = buffer.position() / vertexSize;
|
||||
|
||||
// If the cursor is visible, we append it to the end of our buffer. When rendering, we can either
|
||||
// render n or n+1 quads and so toggle the cursor on and off.
|
||||
DirectFixedWidthFontRenderer.drawCursor( buffer, 0, 0, terminal, !monitor.isColour() );
|
||||
|
||||
buffer.flip();
|
||||
|
||||
vbo.upload( termIndexes, RenderTypes.TERMINAL_WITHOUT_DEPTH.format(), buffer );
|
||||
}
|
||||
|
||||
vbo.bind();
|
||||
FixedWidthFontRenderer.TYPE.format().setupBufferState( 0L );
|
||||
vbo.draw( matrix, FixedWidthFontRenderer.TYPE.mode() );
|
||||
VertexBuffer.unbind();
|
||||
FixedWidthFontRenderer.TYPE.format().clearBufferState();
|
||||
// As with the TBO backend we use getBuffer to flush existing buffers. This time we use TERMINAL_WITHOUT_DEPTH
|
||||
// instead and render a separate depth blocker.
|
||||
bufferSource.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH );
|
||||
RenderTypes.TERMINAL_WITHOUT_DEPTH.setupRenderState();
|
||||
|
||||
vbo.draw(
|
||||
matrix,
|
||||
// As mentioned in the uploading block, render the extra cursor quad if it is visible this frame.
|
||||
// Each quad has an index count of 6.
|
||||
FixedWidthFontRenderer.isCursorVisible( terminal ) && FrameInfo.getGlobalCursorBlink() ? vbo.getIndexCount() + 6 : vbo.getIndexCount()
|
||||
);
|
||||
|
||||
FixedWidthFontRenderer.drawBlocker(
|
||||
matrix, bufferSource.getBuffer( RenderTypes.TERMINAL_BLOCKER ),
|
||||
-xMargin, -yMargin, pixelWidth + xMargin, pixelHeight + yMargin
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static ByteBuffer getBuffer( int capacity )
|
||||
{
|
||||
|
||||
ByteBuffer buffer = backingBuffer;
|
||||
if( buffer == null || buffer.capacity() < capacity )
|
||||
{
|
||||
buffer = backingBuffer = buffer == null ? DirectBuffers.createByteBuffer( capacity ) : DirectBuffers.resizeByteBuffer( buffer, capacity );
|
||||
}
|
||||
|
||||
buffer.clear();
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* 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.render.text;
|
||||
|
||||
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||
import dan200.computercraft.client.util.DirectBuffers;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.core.terminal.TextBuffer;
|
||||
import dan200.computercraft.shared.util.Colour;
|
||||
import dan200.computercraft.shared.util.Palette;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.*;
|
||||
import static org.lwjgl.system.MemoryUtil.memPutByte;
|
||||
import static org.lwjgl.system.MemoryUtil.memPutFloat;
|
||||
|
||||
/**
|
||||
* An optimised copy of {@link FixedWidthFontRenderer} emitter emits directly to a {@link ByteBuffer} rather than
|
||||
* emitting to {@link IVertexBuilder}. This allows us to emit vertices very quickly, when using the VBO renderer.
|
||||
*
|
||||
* There are some limitations here:
|
||||
* <ul>
|
||||
* <li>No transformation matrix (not needed for VBOs).</li>
|
||||
* <li>Only works with {@link DefaultVertexFormats#POSITION_COLOR_TEX}.</li>
|
||||
* <li>The buffer <strong>MUST</strong> be allocated with {@link DirectBuffers}, and not through any other means.</li>
|
||||
* </ul>
|
||||
*
|
||||
* Note this is almost an exact copy of {@link FixedWidthFontRenderer}. While the code duplication is unfortunate,
|
||||
* it is measurably faster than introducing polymorphism into {@link FixedWidthFontRenderer}.
|
||||
*
|
||||
* <strong>IMPORTANT: </strong> When making changes to this class, please check if you need to make the same changes to
|
||||
* {@link FixedWidthFontRenderer}.
|
||||
*/
|
||||
public final class DirectFixedWidthFontRenderer
|
||||
{
|
||||
private DirectFixedWidthFontRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
private static void drawChar( ByteBuffer buffer, float x, float y, int index, byte[] colour )
|
||||
{
|
||||
// Short circuit to avoid the common case - the texture should be blank here after all.
|
||||
if( index == '\0' || index == ' ' ) return;
|
||||
|
||||
int column = index % 16;
|
||||
int row = index / 16;
|
||||
|
||||
int xStart = 1 + column * (FONT_WIDTH + 2);
|
||||
int yStart = 1 + row * (FONT_HEIGHT + 2);
|
||||
|
||||
quad(
|
||||
buffer, x, y, x + FONT_WIDTH, y + FONT_HEIGHT, colour,
|
||||
xStart / WIDTH, yStart / WIDTH, (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH
|
||||
);
|
||||
}
|
||||
|
||||
private static void drawQuad( ByteBuffer emitter, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex )
|
||||
{
|
||||
byte[] colour = palette.getByteColour( getColour( colourIndex, Colour.BLACK ), greyscale );
|
||||
quad( emitter, x, y, x + width, y + height, colour, BACKGROUND_START, BACKGROUND_START, BACKGROUND_END, BACKGROUND_END );
|
||||
}
|
||||
|
||||
private static void drawBackground(
|
||||
@Nonnull ByteBuffer buffer, float x, float y, @Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale,
|
||||
float leftMarginSize, float rightMarginSize, float height
|
||||
)
|
||||
{
|
||||
if( leftMarginSize > 0 )
|
||||
{
|
||||
drawQuad( buffer, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ) );
|
||||
}
|
||||
|
||||
if( rightMarginSize > 0 )
|
||||
{
|
||||
drawQuad( buffer, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, greyscale, backgroundColour.charAt( backgroundColour.length() - 1 ) );
|
||||
}
|
||||
|
||||
// Batch together runs of identical background cells.
|
||||
int blockStart = 0;
|
||||
char blockColour = '\0';
|
||||
for( int i = 0; i < backgroundColour.length(); i++ )
|
||||
{
|
||||
char colourIndex = backgroundColour.charAt( i );
|
||||
if( colourIndex == blockColour ) continue;
|
||||
|
||||
if( blockColour != '\0' )
|
||||
{
|
||||
drawQuad( buffer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour );
|
||||
}
|
||||
|
||||
blockColour = colourIndex;
|
||||
blockStart = i;
|
||||
}
|
||||
|
||||
if( blockColour != '\0' )
|
||||
{
|
||||
drawQuad( buffer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, greyscale, blockColour );
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawString( @Nonnull ByteBuffer buffer, float x, float y, @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nonnull Palette palette, boolean greyscale )
|
||||
{
|
||||
for( int i = 0; i < text.length(); i++ )
|
||||
{
|
||||
byte[] colour = palette.getByteColour( getColour( textColour.charAt( i ), Colour.BLACK ), greyscale );
|
||||
|
||||
int index = text.charAt( i );
|
||||
if( index > 255 ) index = '?';
|
||||
drawChar( buffer, x + i * FONT_WIDTH, y, index, colour );
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawTerminalWithoutCursor(
|
||||
@Nonnull ByteBuffer buffer, float x, float y, @Nonnull Terminal terminal, boolean greyscale,
|
||||
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
|
||||
)
|
||||
{
|
||||
Palette palette = terminal.getPalette();
|
||||
int height = terminal.getHeight();
|
||||
|
||||
// Top and bottom margins
|
||||
drawBackground(
|
||||
buffer, x, y - topMarginSize, terminal.getBackgroundColourLine( 0 ), palette, greyscale,
|
||||
leftMarginSize, rightMarginSize, topMarginSize
|
||||
);
|
||||
|
||||
drawBackground(
|
||||
buffer, x, y + height * FONT_HEIGHT, terminal.getBackgroundColourLine( height - 1 ), palette, greyscale,
|
||||
leftMarginSize, rightMarginSize, bottomMarginSize
|
||||
);
|
||||
|
||||
// The main text
|
||||
for( int i = 0; i < height; i++ )
|
||||
{
|
||||
float rowY = y + FONT_HEIGHT * i;
|
||||
drawBackground(
|
||||
buffer, x, rowY, terminal.getBackgroundColourLine( i ), palette, greyscale,
|
||||
leftMarginSize, rightMarginSize, FONT_HEIGHT
|
||||
);
|
||||
drawString(
|
||||
buffer, x, rowY, terminal.getLine( i ), terminal.getTextColourLine( i ),
|
||||
palette, greyscale
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawCursor( @Nonnull ByteBuffer buffer, float x, float y, @Nonnull Terminal terminal, boolean greyscale )
|
||||
{
|
||||
if( isCursorVisible( terminal ) )
|
||||
{
|
||||
byte[] colour = terminal.getPalette().getByteColour( 15 - terminal.getTextColour(), greyscale );
|
||||
drawChar( buffer, x + terminal.getCursorX() * FONT_WIDTH, y + terminal.getCursorY() * FONT_HEIGHT, '_', colour );
|
||||
}
|
||||
}
|
||||
|
||||
public static int getVertexCount( Terminal terminal )
|
||||
{
|
||||
return (1 + (terminal.getHeight() + 2) * terminal.getWidth() * 2) * 4;
|
||||
}
|
||||
|
||||
private static void quad( ByteBuffer buffer, float x1, float y1, float x2, float y2, byte[] rgba, float u1, float v1, float u2, float v2 )
|
||||
{
|
||||
// Emit a single quad to our buffer. This uses Unsafe (well, LWJGL's MemoryUtil) to directly blit bytes to the
|
||||
// underlying buffer. This allows us to have a single bounds check up-front, rather than one for every write.
|
||||
// This provides significant performance gains, at the cost of well, using Unsafe.
|
||||
// Each vertex is 24 bytes, giving 96 bytes in total. Vertices are of the form (xyz:FFF)(rgba:BBBB)(uv:FF),
|
||||
// which matches the POSITION_COLOR_TEX vertex format.
|
||||
|
||||
int position = buffer.position();
|
||||
long addr = MemoryUtil.memAddress( buffer );
|
||||
|
||||
// We're doing terrible unsafe hacks below, so let's be really sure that what we're doing is reasonable.
|
||||
if( position < 0 || 96 > buffer.limit() - position ) throw new IndexOutOfBoundsException();
|
||||
// Require the pointer to be aligned to a 32-bit boundary.
|
||||
if( (addr & 3) != 0 ) throw new IllegalStateException( "Memory is not aligned" );
|
||||
// Also assert the length of the array. This appears to help elide bounds checks on the array in some circumstances.
|
||||
if( rgba.length != 4 ) throw new IllegalStateException();
|
||||
|
||||
memPutFloat( addr + 0, x1 );
|
||||
memPutFloat( addr + 4, y1 );
|
||||
memPutFloat( addr + 8, 0 );
|
||||
memPutByte( addr + 12, rgba[0] );
|
||||
memPutByte( addr + 13, rgba[1] );
|
||||
memPutByte( addr + 14, rgba[2] );
|
||||
memPutByte( addr + 15, (byte) 255 );
|
||||
memPutFloat( addr + 16, u1 );
|
||||
memPutFloat( addr + 20, v1 );
|
||||
|
||||
memPutFloat( addr + 24, x1 );
|
||||
memPutFloat( addr + 28, y2 );
|
||||
memPutFloat( addr + 32, 0 );
|
||||
memPutByte( addr + 36, rgba[0] );
|
||||
memPutByte( addr + 37, rgba[1] );
|
||||
memPutByte( addr + 38, rgba[2] );
|
||||
memPutByte( addr + 39, (byte) 255 );
|
||||
memPutFloat( addr + 40, u1 );
|
||||
memPutFloat( addr + 44, v2 );
|
||||
|
||||
memPutFloat( addr + 48, x2 );
|
||||
memPutFloat( addr + 52, y2 );
|
||||
memPutFloat( addr + 56, 0 );
|
||||
memPutByte( addr + 60, rgba[0] );
|
||||
memPutByte( addr + 61, rgba[1] );
|
||||
memPutByte( addr + 62, rgba[2] );
|
||||
memPutByte( addr + 63, (byte) 255 );
|
||||
memPutFloat( addr + 64, u2 );
|
||||
memPutFloat( addr + 68, v2 );
|
||||
|
||||
memPutFloat( addr + 72, x2 );
|
||||
memPutFloat( addr + 76, y1 );
|
||||
memPutFloat( addr + 80, 0 );
|
||||
memPutByte( addr + 84, rgba[0] );
|
||||
memPutByte( addr + 85, rgba[1] );
|
||||
memPutByte( addr + 86, rgba[2] );
|
||||
memPutByte( addr + 87, (byte) 255 );
|
||||
memPutFloat( addr + 88, u2 );
|
||||
memPutFloat( addr + 92, v1 );
|
||||
|
||||
// Finally increment the position.
|
||||
buffer.position( position + 96 );
|
||||
|
||||
// Well done for getting to the end of this method. I recommend you take a break and go look at cute puppies.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* 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.render.text;
|
||||
|
||||
import com.mojang.blaze3d.vertex.IVertexBuilder;
|
||||
import dan200.computercraft.client.FrameInfo;
|
||||
import dan200.computercraft.client.render.RenderTypes;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.core.terminal.TextBuffer;
|
||||
import dan200.computercraft.shared.util.Colour;
|
||||
import dan200.computercraft.shared.util.Palette;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.vector.Matrix4f;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
|
||||
|
||||
/**
|
||||
* Handles rendering fixed width text and computer terminals.
|
||||
*
|
||||
* This class has several modes of usage:
|
||||
* <ul>
|
||||
* <li>{@link #drawString}: Drawing basic text without a terminal (such as for printouts). Unlike the other methods,
|
||||
* this accepts a lightmap coordinate as, unlike terminals, printed pages render fullbright.</li>
|
||||
* <li>{@link #drawTerminalWithoutCursor}/{@link #drawCursor}: Draw a terminal without a cursor and then draw the cursor
|
||||
* separately. This is used by the monitor renderer to render the terminal to a VBO and draw the cursor dynamically.
|
||||
* </li>
|
||||
* <li>{@link #drawTerminal}: Draw a terminal with a cursor. This is used by the various computer GUIs to render the
|
||||
* 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>
|
||||
*
|
||||
* <strong>IMPORTANT: </strong> When making changes to this class, please check if you need to make the same changes to
|
||||
* {@link DirectFixedWidthFontRenderer}.
|
||||
*/
|
||||
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_WIDTH = 6;
|
||||
static final float WIDTH = 256.0f;
|
||||
|
||||
static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH;
|
||||
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 static byte byteColour( float c )
|
||||
{
|
||||
return (byte) (int) (c * 255);
|
||||
}
|
||||
|
||||
public static float toGreyscale( double[] rgb )
|
||||
{
|
||||
return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3);
|
||||
}
|
||||
|
||||
public static int getColour( char c, Colour def )
|
||||
{
|
||||
return 15 - Terminal.getColour( c, def );
|
||||
}
|
||||
|
||||
private static void drawChar( Matrix4f transform, IVertexBuilder buffer, 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.
|
||||
if( index == '\0' || index == ' ' ) return;
|
||||
|
||||
int column = index % 16;
|
||||
int row = index / 16;
|
||||
|
||||
int xStart = 1 + column * (FONT_WIDTH + 2);
|
||||
int yStart = 1 + row * (FONT_HEIGHT + 2);
|
||||
|
||||
quad(
|
||||
transform, buffer, x, y, x + FONT_WIDTH, y + FONT_HEIGHT, 0, colour,
|
||||
xStart / WIDTH, yStart / WIDTH, (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH, light
|
||||
);
|
||||
}
|
||||
|
||||
public static void drawQuad( Matrix4f transform, IVertexBuilder buffer, float x, float y, float z, float width, float height, byte[] colour, int light )
|
||||
{
|
||||
quad( transform, buffer, x, y, x + width, y + height, z, colour, BACKGROUND_START, BACKGROUND_START, BACKGROUND_END, BACKGROUND_END, light );
|
||||
}
|
||||
|
||||
private static void drawQuad( Matrix4f transform, IVertexBuilder buffer, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex, int light )
|
||||
{
|
||||
byte[] colour = palette.getByteColour( getColour( colourIndex, Colour.BLACK ), greyscale );
|
||||
drawQuad( transform, buffer, x, y, 0, width, height, colour, light );
|
||||
}
|
||||
|
||||
private static void drawBackground(
|
||||
@Nonnull Matrix4f transform, @Nonnull IVertexBuilder buffer, float x, float y,
|
||||
@Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale,
|
||||
float leftMarginSize, float rightMarginSize, float height, int light
|
||||
)
|
||||
{
|
||||
if( leftMarginSize > 0 )
|
||||
{
|
||||
drawQuad( transform, buffer, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ), light );
|
||||
}
|
||||
|
||||
if( rightMarginSize > 0 )
|
||||
{
|
||||
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.
|
||||
int blockStart = 0;
|
||||
char blockColour = '\0';
|
||||
for( int i = 0; i < backgroundColour.length(); i++ )
|
||||
{
|
||||
char colourIndex = backgroundColour.charAt( i );
|
||||
if( colourIndex == blockColour ) continue;
|
||||
|
||||
if( blockColour != '\0' )
|
||||
{
|
||||
drawQuad( transform, buffer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour, light );
|
||||
}
|
||||
|
||||
blockColour = colourIndex;
|
||||
blockStart = i;
|
||||
}
|
||||
|
||||
if( blockColour != '\0' )
|
||||
{
|
||||
drawQuad( transform, buffer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, greyscale, blockColour, light );
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawString(
|
||||
@Nonnull Matrix4f transform, @Nonnull IVertexBuilder renderer, float x, float y,
|
||||
@Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nonnull Palette palette, boolean greyscale, int light
|
||||
)
|
||||
{
|
||||
for( int i = 0; i < text.length(); i++ )
|
||||
{
|
||||
byte[] colour = palette.getByteColour( getColour( textColour.charAt( i ), Colour.BLACK ), greyscale );
|
||||
|
||||
int index = text.charAt( i );
|
||||
if( index > 255 ) index = '?';
|
||||
drawChar( transform, renderer, x + i * FONT_WIDTH, y, index, colour, light );
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawTerminalWithoutCursor(
|
||||
@Nonnull Matrix4f transform, @Nonnull IVertexBuilder buffer, float x, float y,
|
||||
@Nonnull Terminal terminal, boolean greyscale,
|
||||
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
|
||||
)
|
||||
{
|
||||
Palette palette = terminal.getPalette();
|
||||
int height = terminal.getHeight();
|
||||
|
||||
// Top and bottom margins
|
||||
drawBackground(
|
||||
transform, buffer, x, y - topMarginSize,
|
||||
terminal.getBackgroundColourLine( 0 ), palette, greyscale,
|
||||
leftMarginSize, rightMarginSize, topMarginSize, FULL_BRIGHT_LIGHTMAP
|
||||
);
|
||||
|
||||
drawBackground(
|
||||
transform, buffer, x, y + height * FONT_HEIGHT,
|
||||
terminal.getBackgroundColourLine( height - 1 ), palette, greyscale,
|
||||
leftMarginSize, rightMarginSize, bottomMarginSize, FULL_BRIGHT_LIGHTMAP
|
||||
);
|
||||
|
||||
// The main text
|
||||
for( int i = 0; i < height; i++ )
|
||||
{
|
||||
float rowY = y + FONT_HEIGHT * i;
|
||||
drawBackground(
|
||||
transform, buffer, x, rowY, terminal.getBackgroundColourLine( i ),
|
||||
palette, greyscale, leftMarginSize, rightMarginSize, FONT_HEIGHT, FULL_BRIGHT_LIGHTMAP
|
||||
);
|
||||
|
||||
drawString(
|
||||
transform, buffer, x, rowY, terminal.getLine( i ), terminal.getTextColourLine( i ),
|
||||
palette, greyscale, FULL_BRIGHT_LIGHTMAP
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isCursorVisible( Terminal terminal )
|
||||
{
|
||||
if( !terminal.getCursorBlink() ) return false;
|
||||
|
||||
int cursorX = terminal.getCursorX();
|
||||
int cursorY = terminal.getCursorY();
|
||||
return cursorX >= 0 && cursorX < terminal.getWidth() && cursorY >= 0 && cursorY < terminal.getHeight();
|
||||
}
|
||||
|
||||
public static void drawCursor(
|
||||
@Nonnull Matrix4f transform, @Nonnull IVertexBuilder buffer, float x, float y,
|
||||
@Nonnull Terminal terminal, boolean greyscale
|
||||
)
|
||||
{
|
||||
if( isCursorVisible( terminal ) && FrameInfo.getGlobalCursorBlink() )
|
||||
{
|
||||
byte[] colour = terminal.getPalette().getByteColour( 15 - terminal.getTextColour(), greyscale );
|
||||
drawChar( transform, buffer, x + terminal.getCursorX() * FONT_WIDTH, y + terminal.getCursorY() * FONT_HEIGHT, '_', colour, FULL_BRIGHT_LIGHTMAP );
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawTerminal(
|
||||
@Nonnull Matrix4f transform, @Nonnull IVertexBuilder buffer, float x, float y,
|
||||
@Nonnull Terminal terminal, boolean greyscale,
|
||||
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
|
||||
)
|
||||
{
|
||||
drawTerminalWithoutCursor( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
|
||||
drawCursor( transform, buffer, x, y, terminal, greyscale );
|
||||
}
|
||||
|
||||
public static void drawEmptyTerminal( @Nonnull Matrix4f transform, @Nonnull IVertexBuilder renderer, float x, float y, float width, float height )
|
||||
{
|
||||
drawQuad( transform, renderer, x, y, 0, width, height, BLACK, FULL_BRIGHT_LIGHTMAP );
|
||||
}
|
||||
|
||||
public static void drawBlocker( @Nonnull Matrix4f transform, @Nonnull IVertexBuilder buffer, float x, float y, float width, float height )
|
||||
{
|
||||
drawQuad( transform, buffer, x, y, 0, width, height, BLACK, FULL_BRIGHT_LIGHTMAP );
|
||||
}
|
||||
|
||||
private static void quad( Matrix4f matrix, IVertexBuilder buffer, float x1, float y1, float x2, float y2, float z, byte[] rgba, float u1, float v1, float u2, float v2, int light )
|
||||
{
|
||||
byte r = rgba[0], g = rgba[1], b = rgba[2], a = rgba[3];
|
||||
|
||||
buffer.vertex( matrix, x1, y1, z ).color( r, g, b, a ).uv( u1, v1 ).uv2( light ).endVertex();
|
||||
buffer.vertex( matrix, x1, y2, z ).color( r, g, b, a ).uv( u1, v2 ).uv2( light ).endVertex();
|
||||
buffer.vertex( matrix, x2, y2, z ).color( r, g, b, a ).uv( u2, v2 ).uv2( light ).endVertex();
|
||||
buffer.vertex( matrix, x2, y1, z ).color( r, g, b, a ).uv( u2, v1 ).uv2( light ).endVertex();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.platform.GlStateManager;
|
||||
import org.lwjgl.opengl.GL;
|
||||
import org.lwjgl.opengl.GL15C;
|
||||
import org.lwjgl.opengl.GL45C;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Provides utilities to interact with OpenGL's buffer objects, either using direct state access or binding/unbinding
|
||||
* it.
|
||||
*/
|
||||
public class DirectBuffers
|
||||
{
|
||||
public static final boolean HAS_DSA;
|
||||
|
||||
static
|
||||
{
|
||||
GLCapabilities capabilities = GL.getCapabilities();
|
||||
HAS_DSA = capabilities.OpenGL45 || capabilities.GL_ARB_direct_state_access;
|
||||
}
|
||||
|
||||
public static int createBuffer()
|
||||
{
|
||||
return HAS_DSA ? GL45C.glCreateBuffers() : GL15C.glGenBuffers();
|
||||
}
|
||||
|
||||
public static void setBufferData( int type, int id, ByteBuffer buffer, int flags )
|
||||
{
|
||||
if( HAS_DSA )
|
||||
{
|
||||
GL45C.glNamedBufferData( id, buffer, flags );
|
||||
}
|
||||
else
|
||||
{
|
||||
GlStateManager._glBindBuffer( type, id );
|
||||
GlStateManager._glBufferData( type, buffer, GL15C.GL_STATIC_DRAW );
|
||||
GlStateManager._glBindBuffer( type, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
public static void setEmptyBufferData( int type, int id, int flags )
|
||||
{
|
||||
if( HAS_DSA )
|
||||
{
|
||||
GL45C.glNamedBufferData( id, 0, flags );
|
||||
}
|
||||
else
|
||||
{
|
||||
GlStateManager._glBindBuffer( type, id );
|
||||
GL45C.glBufferData( type, 0, GL15C.GL_STATIC_DRAW );
|
||||
GlStateManager._glBindBuffer( type, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
private static final MemoryUtil.MemoryAllocator ALLOCATOR = MemoryUtil.getAllocator( false );
|
||||
|
||||
public static ByteBuffer createByteBuffer( int size )
|
||||
{
|
||||
long i = ALLOCATOR.malloc( size );
|
||||
if( i == 0L ) throw new OutOfMemoryError( "Failed to allocate " + size + " bytes" );
|
||||
return MemoryUtil.memByteBuffer( i, size );
|
||||
}
|
||||
|
||||
public static ByteBuffer resizeByteBuffer( ByteBuffer buffer, int size )
|
||||
{
|
||||
long i = ALLOCATOR.realloc( MemoryUtil.memAddress0( buffer ), size );
|
||||
if( i == 0L )
|
||||
{
|
||||
throw new OutOfMemoryError( "Failed to resize buffer from " + buffer.capacity() + " bytes to " + size + " bytes" );
|
||||
}
|
||||
|
||||
return MemoryUtil.memByteBuffer( i, size );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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 net.minecraft.client.renderer.vertex.VertexBuffer;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.util.math.vector.Matrix4f;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* A version of {@link VertexBuffer} which allows uploading {@link ByteBuffer}s directly.
|
||||
*/
|
||||
public class DirectVertexBuffer implements AutoCloseable
|
||||
{
|
||||
private int vertextBufferId;
|
||||
private int indexCount;
|
||||
private VertexFormat format;
|
||||
|
||||
public DirectVertexBuffer()
|
||||
{
|
||||
vertextBufferId = DirectBuffers.createBuffer();
|
||||
}
|
||||
|
||||
public void upload( int vertexCount, VertexFormat format, ByteBuffer buffer )
|
||||
{
|
||||
RenderSystem.assertThread( RenderSystem::isOnGameThread );
|
||||
|
||||
DirectBuffers.setBufferData( GL15.GL_ARRAY_BUFFER, vertextBufferId, buffer, GL15.GL_STATIC_DRAW );
|
||||
|
||||
this.format = format;
|
||||
indexCount = vertexCount;
|
||||
}
|
||||
|
||||
public void draw( Matrix4f matrix, int indexCount )
|
||||
{
|
||||
bind();
|
||||
format.setupBufferState( 0 );
|
||||
|
||||
RenderSystem.pushMatrix();
|
||||
RenderSystem.loadIdentity();
|
||||
RenderSystem.multMatrix( matrix );
|
||||
RenderSystem.drawArrays( GL11.GL_QUADS, 0, indexCount );
|
||||
RenderSystem.popMatrix();
|
||||
|
||||
unbind();
|
||||
}
|
||||
|
||||
public int getIndexCount()
|
||||
{
|
||||
return indexCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
if( vertextBufferId >= 0 )
|
||||
{
|
||||
RenderSystem.glDeleteBuffers( vertextBufferId );
|
||||
vertextBufferId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void bind()
|
||||
{
|
||||
RenderSystem.glBindBuffer( GL15.GL_ARRAY_BUFFER, () -> vertextBufferId );
|
||||
}
|
||||
|
||||
private static void unbind()
|
||||
{
|
||||
RenderSystem.glBindBuffer( GL15.GL_ARRAY_BUFFER, () -> 0 );
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,8 @@ import dan200.computercraft.core.computer.TimeoutState;
|
||||
import dan200.computercraft.core.tracking.Tracking;
|
||||
import dan200.computercraft.core.tracking.TrackingField;
|
||||
import dan200.computercraft.shared.util.ThreadUtils;
|
||||
import org.squiddev.cobalt.*;
|
||||
import org.squiddev.cobalt.LuaTable;
|
||||
import org.squiddev.cobalt.*;
|
||||
import org.squiddev.cobalt.compiler.CompileException;
|
||||
import org.squiddev.cobalt.compiler.LoadState;
|
||||
import org.squiddev.cobalt.debug.DebugFrame;
|
||||
|
||||
@@ -57,7 +57,8 @@ public final class ComputerMBean implements DynamicMBean, Tracker
|
||||
{
|
||||
ManagementFactory.getPlatformMBeanServer().registerMBean( instance = new ComputerMBean(), new ObjectName( "dan200.computercraft:type=Computers" ) );
|
||||
}
|
||||
catch( InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException | MalformedObjectNameException e )
|
||||
catch( InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException |
|
||||
MalformedObjectNameException e )
|
||||
{
|
||||
ComputerCraft.log.warn( "Failed to register JMX bean", e );
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import dan200.computercraft.shared.computer.core.IComputer;
|
||||
import dan200.computercraft.shared.computer.core.IContainerComputer;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.inventory.container.Container;
|
||||
import net.minecraft.loot.ConstantRange;
|
||||
import net.minecraft.loot.LootPool;
|
||||
@@ -24,10 +25,7 @@ import net.minecraft.loot.TableLootEntry;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.dedicated.DedicatedServer;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.event.AddReloadListenerEvent;
|
||||
import net.minecraftforge.event.LootTableLoadEvent;
|
||||
import net.minecraftforge.event.RegisterCommandsEvent;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.event.*;
|
||||
import net.minecraftforge.event.entity.player.PlayerContainerEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
@@ -146,4 +144,14 @@ public final class CommonHooks
|
||||
{
|
||||
event.addListener( ResourceMount.RELOAD_LISTENER );
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onMissingEntityMappingsEvent( RegistryEvent.MissingMappings<EntityType<?>> event )
|
||||
{
|
||||
ResourceLocation id = new ResourceLocation( ComputerCraft.MOD_ID, "turtle_player" );
|
||||
for( RegistryEvent.MissingMappings.Mapping<EntityType<?>> mapping : event.getMappings( ComputerCraft.MOD_ID ) )
|
||||
{
|
||||
if( mapping.key.equals( id ) ) mapping.ignore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,6 @@ import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker;
|
||||
import dan200.computercraft.shared.pocket.recipes.PocketComputerUpgradeRecipe;
|
||||
import dan200.computercraft.shared.turtle.blocks.BlockTurtle;
|
||||
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
|
||||
import dan200.computercraft.shared.turtle.core.TurtlePlayer;
|
||||
import dan200.computercraft.shared.turtle.inventory.ContainerTurtle;
|
||||
import dan200.computercraft.shared.turtle.items.ItemTurtle;
|
||||
import dan200.computercraft.shared.turtle.recipes.TurtleRecipe;
|
||||
@@ -70,8 +69,6 @@ import dan200.computercraft.shared.util.*;
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.entity.EntityClassification;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.inventory.container.ContainerType;
|
||||
import net.minecraft.item.*;
|
||||
import net.minecraft.item.crafting.IRecipeSerializer;
|
||||
@@ -296,18 +293,6 @@ public final class Registry
|
||||
ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.speaker = new PocketSpeaker() );
|
||||
}
|
||||
|
||||
public static class ModEntities
|
||||
{
|
||||
static final DeferredRegister<EntityType<?>> ENTITIES = DeferredRegister.create( ForgeRegistries.ENTITIES, ComputerCraft.MOD_ID );
|
||||
|
||||
public static final RegistryObject<EntityType<TurtlePlayer>> TURTLE_PLAYER = ENTITIES.register( "turtle_player", () ->
|
||||
EntityType.Builder.<TurtlePlayer>createNothing( EntityClassification.MISC )
|
||||
.noSave()
|
||||
.noSummon()
|
||||
.sized( 0, 0 )
|
||||
.build( ComputerCraft.MOD_ID + ":turtle_player" ) );
|
||||
}
|
||||
|
||||
public static class ModContainers
|
||||
{
|
||||
static final DeferredRegister<ContainerType<?>> CONTAINERS = DeferredRegister.create( ForgeRegistries.CONTAINERS, ComputerCraft.MOD_ID );
|
||||
@@ -418,7 +403,6 @@ public final class Registry
|
||||
ModBlocks.BLOCKS.register( bus );
|
||||
ModTiles.TILES.register( bus );
|
||||
ModItems.ITEMS.register( bus );
|
||||
ModEntities.ENTITIES.register( bus );
|
||||
ModContainers.CONTAINERS.register( bus );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public abstract class BlockComputerBase<T extends TileComputerBase> extends Bloc
|
||||
super.onPlace( state, world, pos, oldState, isMoving );
|
||||
|
||||
TileEntity tile = world.getBlockEntity( pos );
|
||||
if( tile instanceof TileComputerBase ) ((TileComputerBase) tile).updateInputsImmediately( );
|
||||
if( tile instanceof TileComputerBase ) ((TileComputerBase) tile).updateInputsImmediately();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -97,7 +97,7 @@ public class TileCommandComputer extends TileComputer
|
||||
}
|
||||
|
||||
return new CommandSource( receiver,
|
||||
new Vector3d( worldPosition.getX() + 0.5, worldPosition.getY() + 0.5, worldPosition.getZ() + 0.5 ), Vector2f.ZERO,
|
||||
Vector3d.atCenterOf( worldPosition ), Vector2f.ZERO,
|
||||
(ServerWorld) getLevel(), 2,
|
||||
name, new StringTextComponent( name ),
|
||||
getLevel().getServer(), null
|
||||
|
||||
@@ -160,6 +160,7 @@ public class UploadFileMessage extends ComputerServerMessage
|
||||
contents.position( currentOffset ).limit( currentOffset + canWrite );
|
||||
slices.add( new FileSlice( fileId, currentOffset, contents.slice() ) );
|
||||
currentOffset += canWrite;
|
||||
remaining -= canWrite;
|
||||
}
|
||||
|
||||
contents.position( 0 ).limit( capacity );
|
||||
|
||||
@@ -45,7 +45,7 @@ public class GenericPeripheralProvider
|
||||
|
||||
for( Capability<?> capability : capabilities )
|
||||
{
|
||||
LazyOptional<?> wrapper = tile.getCapability( capability );
|
||||
LazyOptional<?> wrapper = CapabilityUtil.getCapability( tile, capability, side );
|
||||
wrapper.ifPresent( contents -> {
|
||||
List<NamedMethod<PeripheralMethod>> capabilityMethods = PeripheralMethod.GENERATOR.getMethods( contents.getClass() );
|
||||
if( capabilityMethods.isEmpty() ) return;
|
||||
|
||||
@@ -60,8 +60,7 @@ public class TileCable extends TileGeneric
|
||||
@Override
|
||||
public Vector3d getPosition()
|
||||
{
|
||||
BlockPos pos = getBlockPos();
|
||||
return new Vector3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
|
||||
return Vector3d.atCenterOf( getBlockPos() );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -106,8 +105,7 @@ public class TileCable extends TileGeneric
|
||||
@Override
|
||||
public Vector3d getPosition()
|
||||
{
|
||||
BlockPos pos = getBlockPos().relative( modemDirection );
|
||||
return new Vector3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
|
||||
return Vector3d.atCenterOf( getBlockPos().relative( modemDirection ) );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
||||
@@ -87,8 +87,7 @@ public class TileWiredModemFull extends TileGeneric
|
||||
@Override
|
||||
public Vector3d getPosition()
|
||||
{
|
||||
BlockPos pos = entity.getBlockPos();
|
||||
return new Vector3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
|
||||
return Vector3d.atCenterOf( entity.getBlockPos() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,8 +417,7 @@ public class TileWiredModemFull extends TileGeneric
|
||||
@Override
|
||||
public Vector3d getPosition()
|
||||
{
|
||||
BlockPos pos = getBlockPos().relative( side );
|
||||
return new Vector3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
|
||||
return Vector3d.atCenterOf( getBlockPos().relative( side ) );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
||||
@@ -14,7 +14,6 @@ import dan200.computercraft.shared.util.TickScheduler;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.tileentity.TileEntityType;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
@@ -48,8 +47,7 @@ public class TileWirelessModem extends TileGeneric
|
||||
@Override
|
||||
public Vector3d getPosition()
|
||||
{
|
||||
BlockPos pos = entity.getBlockPos().relative( entity.modemDirection );
|
||||
return new Vector3d( pos.getX(), pos.getY(), pos.getZ() );
|
||||
return Vector3d.atLowerCornerOf( entity.getBlockPos().relative( entity.modemDirection ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,9 +7,9 @@ package dan200.computercraft.shared.peripheral.monitor;
|
||||
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.client.util.DirectBuffers;
|
||||
import dan200.computercraft.client.util.DirectVertexBuffer;
|
||||
import dan200.computercraft.shared.common.ClientTerminal;
|
||||
import net.minecraft.client.renderer.vertex.VertexBuffer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
@@ -33,7 +33,8 @@ public final class ClientMonitor extends ClientTerminal
|
||||
|
||||
public int tboBuffer;
|
||||
public int tboTexture;
|
||||
public VertexBuffer buffer;
|
||||
public int tboUniform;
|
||||
public DirectVertexBuffer buffer;
|
||||
|
||||
public ClientMonitor( boolean colour, TileMonitor origin )
|
||||
{
|
||||
@@ -64,15 +65,15 @@ public final class ClientMonitor extends ClientTerminal
|
||||
|
||||
deleteBuffers();
|
||||
|
||||
tboBuffer = GlStateManager._glGenBuffers();
|
||||
GlStateManager._glBindBuffer( GL31.GL_TEXTURE_BUFFER, tboBuffer );
|
||||
GL15.glBufferData( GL31.GL_TEXTURE_BUFFER, 0, GL15.GL_STATIC_DRAW );
|
||||
tboBuffer = DirectBuffers.createBuffer();
|
||||
DirectBuffers.setEmptyBufferData( GL31.GL_TEXTURE_BUFFER, tboBuffer, GL15.GL_STATIC_DRAW );
|
||||
tboTexture = GlStateManager._genTexture();
|
||||
GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, tboTexture );
|
||||
GL31.glTexBuffer( GL31.GL_TEXTURE_BUFFER, GL30.GL_R8UI, tboBuffer );
|
||||
GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, 0 );
|
||||
|
||||
GlStateManager._glBindBuffer( GL31.GL_TEXTURE_BUFFER, 0 );
|
||||
tboUniform = DirectBuffers.createBuffer();
|
||||
DirectBuffers.setEmptyBufferData( GL31.GL_UNIFORM_BUFFER, tboUniform, GL15.GL_STATIC_DRAW );
|
||||
|
||||
addMonitor();
|
||||
return true;
|
||||
@@ -82,7 +83,7 @@ public final class ClientMonitor extends ClientTerminal
|
||||
if( buffer != null ) return false;
|
||||
|
||||
deleteBuffers();
|
||||
buffer = new VertexBuffer( FixedWidthFontRenderer.TYPE.format() );
|
||||
buffer = new DirectVertexBuffer();
|
||||
addMonitor();
|
||||
return true;
|
||||
|
||||
@@ -114,6 +115,12 @@ public final class ClientMonitor extends ClientTerminal
|
||||
tboTexture = 0;
|
||||
}
|
||||
|
||||
if( tboUniform != 0 )
|
||||
{
|
||||
RenderSystem.glDeleteBuffers( tboUniform );
|
||||
tboUniform = 0;
|
||||
}
|
||||
|
||||
if( buffer != null )
|
||||
{
|
||||
buffer.close();
|
||||
|
||||
@@ -7,6 +7,7 @@ package dan200.computercraft.shared.peripheral.monitor;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.client.render.TileEntityMonitorRenderer;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import org.lwjgl.opengl.GL;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@@ -47,39 +48,24 @@ public enum MonitorRenderer
|
||||
public static MonitorRenderer current()
|
||||
{
|
||||
MonitorRenderer current = ComputerCraft.monitorRenderer;
|
||||
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;
|
||||
default:
|
||||
return current;
|
||||
}
|
||||
if( current == BEST ) current = ComputerCraft.monitorRenderer = best();
|
||||
return current;
|
||||
}
|
||||
|
||||
private static MonitorRenderer best()
|
||||
{
|
||||
checkCapabilities();
|
||||
return textureBuffer ? TBO : VBO;
|
||||
}
|
||||
if( !GL.getCapabilities().OpenGL31 )
|
||||
{
|
||||
ComputerCraft.log.warn( "Texture buffers are not supported on your graphics card. Falling back to VBO monitor renderer." );
|
||||
return VBO;
|
||||
}
|
||||
|
||||
private static boolean initialised = false;
|
||||
private static boolean textureBuffer = false;
|
||||
if( ModList.get().isLoaded( "optifine" ) )
|
||||
{
|
||||
ComputerCraft.log.warn( "Optifine is loaded, assuming shaders are being used. Falling back to VBO monitor renderer." );
|
||||
return VBO;
|
||||
}
|
||||
|
||||
private static void checkCapabilities()
|
||||
{
|
||||
if( initialised ) return;
|
||||
|
||||
textureBuffer = GL.getCapabilities().OpenGL31;
|
||||
initialised = true;
|
||||
return TBO;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.ChunkStatus;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.event.world.ChunkWatchEvent;
|
||||
@@ -47,8 +46,10 @@ public final class MonitorWatcher
|
||||
@SubscribeEvent
|
||||
public static void onWatch( ChunkWatchEvent.Watch event )
|
||||
{
|
||||
// Get the current chunk if it has been loaded. This is safe as, if the chunk hasn't been loaded yet, then the
|
||||
// monitor will have no contents, and so we won't need to send an update anyway.
|
||||
ChunkPos chunkPos = event.getPos();
|
||||
Chunk chunk = (Chunk) event.getWorld().getChunk( chunkPos.x, chunkPos.z, ChunkStatus.FULL, false );
|
||||
Chunk chunk = event.getWorld().getChunkSource().getChunkNow( chunkPos.x, chunkPos.z );
|
||||
if( chunk == null ) return;
|
||||
|
||||
for( TileEntity te : chunk.getBlockEntities().values() )
|
||||
|
||||
@@ -70,6 +70,11 @@ public class TileMonitor extends TileGeneric
|
||||
private int xIndex = 0;
|
||||
private int yIndex = 0;
|
||||
|
||||
private BlockPos bbPos;
|
||||
private BlockState bbState;
|
||||
private int bbX, bbY, bbWidth, bbHeight;
|
||||
private AxisAlignedBB boundingBox;
|
||||
|
||||
public TileMonitor( TileEntityType<? extends TileMonitor> type, boolean advanced )
|
||||
{
|
||||
super( type );
|
||||
@@ -624,9 +629,25 @@ public class TileMonitor extends TileGeneric
|
||||
@Override
|
||||
public AxisAlignedBB 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 endPos = toWorldPos( width, height );
|
||||
return new AxisAlignedBB(
|
||||
return boundingBox = new AxisAlignedBB(
|
||||
Math.min( startPos.getX(), endPos.getX() ),
|
||||
Math.min( startPos.getY(), endPos.getY() ),
|
||||
Math.min( startPos.getZ(), endPos.getZ() ),
|
||||
|
||||
@@ -13,7 +13,6 @@ import dan200.computercraft.shared.util.CapabilityUtil;
|
||||
import net.minecraft.tileentity.ITickableTileEntity;
|
||||
import net.minecraft.tileentity.TileEntityType;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
@@ -90,8 +89,7 @@ public class TileSpeaker extends TileGeneric implements ITickableTileEntity
|
||||
@Override
|
||||
public Vector3d getPosition()
|
||||
{
|
||||
BlockPos pos = speaker.getBlockPos();
|
||||
return new Vector3d( pos.getX(), pos.getY(), pos.getZ() );
|
||||
return Vector3d.atCenterOf( speaker.getBlockPos() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -69,6 +69,7 @@ import java.util.Optional;
|
||||
* accessible by accessing the `"left"` or `"right"` peripheral.
|
||||
*
|
||||
* [Turtle Graphics]: https://en.wikipedia.org/wiki/Turtle_graphics "Turtle graphics"
|
||||
*
|
||||
* @cc.module turtle
|
||||
* @cc.since 1.3
|
||||
*/
|
||||
|
||||
@@ -8,14 +8,11 @@ package dan200.computercraft.shared.turtle.core;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||
import dan200.computercraft.shared.Registry;
|
||||
import dan200.computercraft.shared.util.DirectionUtil;
|
||||
import dan200.computercraft.shared.util.FakeNetHandler;
|
||||
import dan200.computercraft.shared.util.InventoryUtil;
|
||||
import dan200.computercraft.shared.util.WorldUtil;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntitySize;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.Pose;
|
||||
import net.minecraft.entity.passive.horse.AbstractHorseEntity;
|
||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||
@@ -54,7 +51,6 @@ public final class TurtlePlayer extends FakePlayer
|
||||
GameProfile profile = turtle.getOwningPlayer();
|
||||
|
||||
TurtlePlayer player = new TurtlePlayer( world, getProfile( profile ) );
|
||||
player.connection = new FakeNetHandler( player );
|
||||
player.setState( turtle );
|
||||
|
||||
if( profile != null && profile.getId() != null )
|
||||
@@ -203,13 +199,6 @@ public final class TurtlePlayer extends FakePlayer
|
||||
inventory.setChanged();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public EntityType<?> getType()
|
||||
{
|
||||
return Registry.ModEntities.TURTLE_PLAYER.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3d position()
|
||||
{
|
||||
|
||||
@@ -15,7 +15,6 @@ import dan200.computercraft.shared.Registry;
|
||||
import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral;
|
||||
import net.minecraft.client.renderer.model.ModelResourceLocation;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
@@ -47,8 +46,7 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade
|
||||
@Override
|
||||
public Vector3d getPosition()
|
||||
{
|
||||
BlockPos pos = turtle.getPosition();
|
||||
return new Vector3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
|
||||
return Vector3d.atCenterOf( turtle.getPosition() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,9 +5,13 @@
|
||||
*/
|
||||
package dan200.computercraft.shared.util;
|
||||
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.common.util.NonNullConsumer;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public final class CapabilityUtil
|
||||
@@ -57,4 +61,21 @@ public final class CapabilityUtil
|
||||
{
|
||||
return !p.isPresent() ? null : p.orElseThrow( NullPointerException::new );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a capability, preferring the internal/null side but falling back to a given side if a mod doesn't support
|
||||
* the internal one.
|
||||
*
|
||||
* @param provider The capability provider to get the capability from.
|
||||
* @param capability The capability to get.
|
||||
* @param side The side we'll fall back to.
|
||||
* @param <T> The type of the underlying capability.
|
||||
* @return The extracted capability, if present.
|
||||
*/
|
||||
@Nonnull
|
||||
public static <T> LazyOptional<T> getCapability( ICapabilityProvider provider, Capability<T> capability, Direction side )
|
||||
{
|
||||
LazyOptional<T> cap = provider.getCapability( capability );
|
||||
return cap.isPresent() ? cap : provider.getCapability( capability, side );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,348 +0,0 @@
|
||||
/*
|
||||
* 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.shared.util;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.util.concurrent.Future;
|
||||
import io.netty.util.concurrent.GenericFutureListener;
|
||||
import net.minecraft.network.*;
|
||||
import net.minecraft.network.play.ServerPlayNetHandler;
|
||||
import net.minecraft.network.play.client.*;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class FakeNetHandler extends ServerPlayNetHandler
|
||||
{
|
||||
public FakeNetHandler( @Nonnull FakePlayer player )
|
||||
{
|
||||
super( player.getLevel().getServer(), new FakeNetworkManager(), player );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect( @Nonnull ITextComponent reason )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnect( @Nonnull ITextComponent reason )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send( @Nonnull IPacket<?> packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send( @Nonnull IPacket<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> whenSent )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePlayerInput( @Nonnull CInputPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMoveVehicle( @Nonnull CMoveVehiclePacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleAcceptTeleportPacket( @Nonnull CConfirmTeleportPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSeenAdvancements( @Nonnull CSeenAdvancementsPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCustomCommandSuggestions( @Nonnull CTabCompletePacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSetCommandBlock( @Nonnull CUpdateCommandBlockPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSetCommandMinecart( @Nonnull CUpdateMinecartCommandBlockPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePickItem( @Nonnull CPickItemPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRenameItem( @Nonnull CRenameItemPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSetBeaconPacket( @Nonnull CUpdateBeaconPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSetStructureBlock( @Nonnull CUpdateStructureBlockPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSetJigsawBlock( @Nonnull CUpdateJigsawBlockPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSelectTrade( @Nonnull CSelectTradePacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEditBook( @Nonnull CEditBookPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEntityTagQuery( @Nonnull CQueryEntityNBTPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleBlockEntityTagQuery( @Nonnull CQueryTileEntityNBTPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMovePlayer( @Nonnull CPlayerPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePlayerAction( @Nonnull CPlayerDiggingPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleUseItemOn( @Nonnull CPlayerTryUseItemOnBlockPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleUseItem( @Nonnull CPlayerTryUseItemPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTeleportToEntityPacket( @Nonnull CSpectatePacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleResourcePackResponse( @Nonnull CResourcePackStatusPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePaddleBoat( @Nonnull CSteerBoatPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSetCarriedItem( @Nonnull CHeldItemChangePacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleChat( @Nonnull CChatMessagePacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleAnimate( @Nonnull CAnimateHandPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePlayerCommand( @Nonnull CEntityActionPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleInteract( @Nonnull CUseEntityPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleClientCommand( @Nonnull CClientStatusPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleContainerClose( @Nonnull CCloseWindowPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleContainerClick( @Nonnull CClickWindowPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePlaceRecipe( @Nonnull CPlaceRecipePacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleContainerButtonClick( @Nonnull CEnchantItemPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSetCreativeModeSlot( @Nonnull CCreativeInventoryActionPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleContainerAck( @Nonnull CConfirmTransactionPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSignUpdate( @Nonnull CUpdateSignPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleKeepAlive( @Nonnull CKeepAlivePacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePlayerAbilities( @Nonnull CPlayerAbilitiesPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleClientInformation( @Nonnull CClientSettingsPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCustomPayload( @Nonnull CCustomPayloadPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleChangeDifficulty( @Nonnull CSetDifficultyPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleLockDifficulty( @Nonnull CLockDifficultyPacket packet )
|
||||
{
|
||||
}
|
||||
|
||||
private static class FakeNetworkManager extends NetworkManager
|
||||
{
|
||||
private INetHandler handler;
|
||||
private ITextComponent closeReason;
|
||||
|
||||
FakeNetworkManager()
|
||||
{
|
||||
super( PacketDirection.CLIENTBOUND );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive( @Nonnull ChannelHandlerContext context )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProtocol( @Nonnull ProtocolType state )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive( @Nonnull ChannelHandlerContext context )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught( @Nonnull ChannelHandlerContext context, @Nonnull Throwable err )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0( @Nonnull ChannelHandlerContext context, @Nonnull IPacket<?> packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListener( @Nonnull INetHandler handler )
|
||||
{
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send( @Nonnull IPacket<?> packet )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send( @Nonnull IPacket<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> whenSent )
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect( @Nonnull ITextComponent message )
|
||||
{
|
||||
closeReason = message;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public INetHandler getPacketListener()
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ITextComponent getDisconnectedReason()
|
||||
{
|
||||
return closeReason;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadOnly()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupCompression( int threshold )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,21 +45,17 @@ public final class IDAssigner
|
||||
return ServerLifecycleHooks.getCurrentServer().getWorldPath( FOLDER ).toFile();
|
||||
}
|
||||
|
||||
private static MinecraftServer getCachedServer()
|
||||
private static boolean hasServerChanged()
|
||||
{
|
||||
if( server == null ) return null;
|
||||
if( server == null ) return true;
|
||||
|
||||
MinecraftServer currentServer = server.get();
|
||||
if( currentServer == null ) return null;
|
||||
|
||||
if( currentServer != ServerLifecycleHooks.getCurrentServer() ) return null;
|
||||
return currentServer;
|
||||
return currentServer == null || currentServer != ServerLifecycleHooks.getCurrentServer();
|
||||
}
|
||||
|
||||
public static synchronized int getNextId( String kind )
|
||||
{
|
||||
MinecraftServer currentServer = getCachedServer();
|
||||
if( currentServer == null )
|
||||
if( hasServerChanged() )
|
||||
{
|
||||
// The server has changed, refetch our ID map
|
||||
server = new WeakReference<>( ServerLifecycleHooks.getCurrentServer() );
|
||||
@@ -68,23 +64,22 @@ public final class IDAssigner
|
||||
dir.mkdirs();
|
||||
|
||||
// Load our ID file from disk
|
||||
Map<String, Integer> newIds = null;
|
||||
idFile = new File( dir, "ids.json" ).toPath();
|
||||
if( Files.isRegularFile( idFile ) )
|
||||
{
|
||||
try( Reader reader = Files.newBufferedReader( idFile, StandardCharsets.UTF_8 ) )
|
||||
{
|
||||
ids = GSON.fromJson( reader, ID_TOKEN );
|
||||
newIds = GSON.fromJson( reader, ID_TOKEN );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
ComputerCraft.log.error( "Cannot load id file '" + idFile + "'", e );
|
||||
ids = new HashMap<>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ids = new HashMap<>();
|
||||
}
|
||||
|
||||
if( newIds == null ) newIds = new HashMap<>();
|
||||
ids = newIds;
|
||||
}
|
||||
|
||||
Integer existing = ids.get( kind );
|
||||
|
||||
@@ -5,13 +5,18 @@
|
||||
*/
|
||||
package dan200.computercraft.shared.util;
|
||||
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class Palette
|
||||
{
|
||||
private static final int PALETTE_SIZE = 16;
|
||||
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();
|
||||
|
||||
@@ -19,16 +24,23 @@ public class Palette
|
||||
{
|
||||
// Get the default palette
|
||||
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 )
|
||||
{
|
||||
if( i >= 0 && i < colours.length )
|
||||
{
|
||||
colours[i][0] = r;
|
||||
colours[i][1] = g;
|
||||
colours[i][2] = b;
|
||||
}
|
||||
if( i < 0 || i >= colours.length ) return;
|
||||
colours[i][0] = r;
|
||||
colours[i][1] = g;
|
||||
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 )
|
||||
@@ -38,19 +50,29 @@ public class Palette
|
||||
|
||||
public double[] getColour( int i )
|
||||
{
|
||||
if( i >= 0 && i < colours.length )
|
||||
{
|
||||
return colours[i];
|
||||
}
|
||||
return null;
|
||||
return i >= 0 && i < colours.length ? colours[i] : 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 )
|
||||
{
|
||||
if( i >= 0 && i < colours.length )
|
||||
{
|
||||
setColour( i, Colour.VALUES[i] );
|
||||
}
|
||||
if( i >= 0 && i < colours.length ) setColour( i, Colour.VALUES[i] );
|
||||
}
|
||||
|
||||
public void resetColours()
|
||||
@@ -89,9 +111,12 @@ public class Palette
|
||||
|
||||
public void read( PacketBuffer 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++ )
|
||||
{
|
||||
colours[i] = decodeRGB8( rgb8[i] );
|
||||
double[] colours = decodeRGB8( rgb8[i] );
|
||||
setColour( i, colours[0], colours[1], colours[2] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,16 @@
|
||||
#define FONT_HEIGHT 9.0
|
||||
|
||||
uniform sampler2D u_font;
|
||||
uniform int u_width;
|
||||
uniform int u_height;
|
||||
uniform usamplerBuffer u_tbo;
|
||||
uniform vec3 u_palette[16];
|
||||
|
||||
layout(std140) uniform u_monitor {
|
||||
vec3 u_palette[16];
|
||||
int u_width;
|
||||
int u_height;
|
||||
ivec2 u_cursorPos;
|
||||
int u_cursorColour;
|
||||
};
|
||||
uniform int u_cursorBlink;
|
||||
|
||||
in vec2 f_pos;
|
||||
|
||||
@@ -19,6 +25,10 @@ vec2 texture_corner(int index) {
|
||||
return vec2(x, y);
|
||||
}
|
||||
|
||||
vec4 recolour(vec4 texture, int colour) {
|
||||
return vec4(texture.rgb * u_palette[colour], texture.rgba);
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 term_pos = vec2(f_pos.x / FONT_WIDTH, f_pos.y / FONT_HEIGHT);
|
||||
vec2 corner = floor(term_pos);
|
||||
@@ -35,6 +45,12 @@ void main() {
|
||||
int bg = int(texelFetch(u_tbo, index + 2).r);
|
||||
|
||||
vec2 pos = (term_pos - corner) * vec2(FONT_WIDTH, FONT_HEIGHT);
|
||||
vec4 img = texture(u_font, (texture_corner(character) + pos) / 256.0);
|
||||
colour = vec4(mix(u_palette[bg], img.rgb * u_palette[fg], img.a * mult), 1.0);
|
||||
vec4 charTex = recolour(texture(u_font, (texture_corner(character) + pos) / 256.0), fg);
|
||||
|
||||
// Applies the cursor on top of the current character if we're blinking and in the current cursor's cell. We do it
|
||||
// this funky way to avoid branches.
|
||||
vec4 cursorTex = recolour(texture(u_font, (texture_corner(95) + pos) / 256.0), u_cursorColour); // 95 = '_'
|
||||
vec4 img = mix(charTex, cursorTex, cursorTex.a * float(u_cursorBlink) * (u_cursorPos == cell ? 1.0 : 0.0));
|
||||
|
||||
colour = vec4(mix(u_palette[bg], img.rgb, img.a * mult), 1.0);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"parent": "minecraft:recipes/root",
|
||||
"rewards": {
|
||||
"recipes": [ "computercraft:normal_turtle_normal" ]
|
||||
"recipes": [ "computercraft:turtle_normal" ]
|
||||
},
|
||||
"criteria": {
|
||||
"has_normal": {
|
||||
|
||||
@@ -268,7 +268,7 @@ end
|
||||
--- Combine a three-colour RGB value into one hexadecimal representation.
|
||||
--
|
||||
-- @tparam number r The red channel, should be between 0 and 1.
|
||||
-- @tparam number g The red channel, should be between 0 and 1.
|
||||
-- @tparam number g The green channel, should be between 0 and 1.
|
||||
-- @tparam number b The blue channel, should be between 0 and 1.
|
||||
-- @treturn number The combined hexadecimal colour.
|
||||
-- @usage
|
||||
@@ -291,7 +291,7 @@ end
|
||||
--
|
||||
-- @tparam number rgb The combined hexadecimal colour.
|
||||
-- @treturn number The red channel, will be between 0 and 1.
|
||||
-- @treturn number The red channel, will be between 0 and 1.
|
||||
-- @treturn number The green channel, will be between 0 and 1.
|
||||
-- @treturn number The blue channel, will be between 0 and 1.
|
||||
-- @usage
|
||||
-- ```lua
|
||||
|
||||
@@ -217,9 +217,10 @@ end
|
||||
channel. The message will be received by every device listening to rednet.
|
||||
|
||||
@param message The message to send. This should not contain coroutines or
|
||||
functions, as they will be converted to @{nil}. @tparam[opt] string protocol
|
||||
The "protocol" to send this message under. When using @{rednet.receive} one can
|
||||
filter to only receive messages sent under a particular protocol.
|
||||
functions, as they will be converted to @{nil}.
|
||||
@tparam[opt] string protocol The "protocol" to send this message under.
|
||||
When using @{rednet.receive} one can filter to only receive messages sent
|
||||
under a particular protocol.
|
||||
@see rednet.receive
|
||||
@changed 1.6 Added protocol parameter.
|
||||
@usage Broadcast the words "Hello, world!" to every computer using rednet.
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
# New features in CC: Tweaked 1.100.5
|
||||
|
||||
* Generic peripherals now use capabilities on the given side if one isn't provided on the internal side.
|
||||
* Improve performance of monitor rendering.
|
||||
|
||||
Several bug fixes:
|
||||
* Various documentation fixes (bclindner, Hasaabitt)
|
||||
* Speaker sounds are now correctly positioned on the centre of the speaker block.
|
||||
|
||||
# New features in CC: Tweaked 1.100.4
|
||||
|
||||
Several bug fixes:
|
||||
* Fix the monitor watching blocking the main thread when chunks are slow to load.
|
||||
|
||||
# New features in CC: Tweaked 1.100.3
|
||||
|
||||
Several bug fixes:
|
||||
* Fix client disconnect when uploading large files.
|
||||
* Correctly handling empty computer ID file.
|
||||
* Fix the normal turtle recipe not being unlocked.
|
||||
* Remove turtle fake EntityType.
|
||||
|
||||
# New features in CC: Tweaked 1.100.2
|
||||
|
||||
Several bug fixes:
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
New features in CC: Tweaked 1.100.2
|
||||
New features in CC: Tweaked 1.100.5
|
||||
|
||||
* Generic peripherals now use capabilities on the given side if one isn't provided on the internal side.
|
||||
* Improve performance of monitor rendering.
|
||||
|
||||
Several bug fixes:
|
||||
* Fix wired modems swapping the modem/peripheral block state.
|
||||
* Remove debugging logging line from `turtle.attack`.
|
||||
* Various documentation fixes (bclindner, Hasaabitt)
|
||||
* Speaker sounds are now correctly positioned on the centre of the speaker block.
|
||||
|
||||
Type "help changelog" to see the full version history.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
-- It allows you to @{run|start programs}, @{setCompletionFunction|add
|
||||
-- completion for a program}, and much more.
|
||||
--
|
||||
-- @{shell} is not a "true" API. Instead, it is a standard program, which its
|
||||
-- @{shell} is not a "true" API. Instead, it is a standard program, which injects its
|
||||
-- API into the programs that it launches. This allows for multiple shells to
|
||||
-- run at the same time, but means that the API is not available in the global
|
||||
-- environment, and so is unavailable to other @{os.loadAPI|APIs}.
|
||||
@@ -242,8 +242,8 @@ end
|
||||
-- @since 1.2
|
||||
-- @usage Locate the `hello` program.
|
||||
--
|
||||
-- shell.resolveProgram("hello")
|
||||
-- -- => rom/programs/fun/hello.lua
|
||||
-- shell.resolveProgram("hello")
|
||||
-- -- => rom/programs/fun/hello.lua
|
||||
function shell.resolveProgram(command)
|
||||
expect(1, command, "string")
|
||||
-- Substitute aliases firsts
|
||||
|
||||
@@ -23,8 +23,6 @@ table.pretty-table th {
|
||||
|
||||
pre.highlight.highlight-lua {
|
||||
position: relative;
|
||||
background: var(--background-2);
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.example-run {
|
||||
|
||||
Reference in New Issue
Block a user