mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-12-13 03:30:29 +00:00
Rework rendering of in-hand pocket computers (#215)
Rendering an item worked in principle, but had several caveats: - The terminal did not fit well within the item's texture, so we had a rather large border. - The "correctness" of this was very tied to Minecraft's item rendering code. This changed a little in 1.13, causing problems like #208. Instead we effectively reuse the computer GUI rendering code, though also handling coloured pocket computers and rendering the modem light. This fixes #208, and hopefully fixes #212.
This commit is contained in:
parent
b11beb508b
commit
114f913bf8
@ -24,9 +24,10 @@ import java.io.IOException;
|
||||
|
||||
public class GuiComputer extends GuiContainer
|
||||
{
|
||||
private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/corners.png" );
|
||||
private static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( "computercraft", "textures/gui/corners_advanced.png" );
|
||||
private static final ResourceLocation BACKGROUND_COMMAND = new ResourceLocation( "computercraft", "textures/gui/corners_command.png" );
|
||||
public static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners.png" );
|
||||
public static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_advanced.png" );
|
||||
public static final ResourceLocation BACKGROUND_COMMAND = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_command.png" );
|
||||
public static final ResourceLocation BACKGROUND_COLOUR = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_colour.png" );
|
||||
|
||||
private final ComputerFamily m_family;
|
||||
private final ClientComputer m_computer;
|
||||
@ -158,7 +159,7 @@ public class GuiComputer extends GuiContainer
|
||||
{
|
||||
case Normal:
|
||||
default:
|
||||
mc.getTextureManager().bindTexture( BACKGROUND );
|
||||
mc.getTextureManager().bindTexture( BACKGROUND_NORMAL );
|
||||
break;
|
||||
case Advanced:
|
||||
mc.getTextureManager().bindTexture( BACKGROUND_ADVANCED );
|
||||
@ -169,12 +170,12 @@ public class GuiComputer extends GuiContainer
|
||||
}
|
||||
|
||||
drawTexturedModalRect( startX - 12, startY - 12, 12, 28, 12, 12 );
|
||||
drawTexturedModalRect( startX - 12, endY, 12, 40, 12, 16 );
|
||||
drawTexturedModalRect( startX - 12, endY, 12, 40, 12, 12 );
|
||||
drawTexturedModalRect( endX, startY - 12, 24, 28, 12, 12 );
|
||||
drawTexturedModalRect( endX, endY, 24, 40, 12, 16 );
|
||||
drawTexturedModalRect( endX, endY, 24, 40, 12, 12 );
|
||||
|
||||
drawTexturedModalRect( startX, startY - 12, 0, 0, endX - startX, 12 );
|
||||
drawTexturedModalRect( startX, endY, 0, 12, endX - startX, 16 );
|
||||
drawTexturedModalRect( startX, endY, 0, 12, endX - startX, 12 );
|
||||
|
||||
drawTexturedModalRect( startX - 12, startY, 0, 28, 12, endY - startY );
|
||||
drawTexturedModalRect( endX, startY, 36, 28, 12, endY - startY );
|
||||
|
@ -12,25 +12,24 @@ import dan200.computercraft.client.gui.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.core.terminal.TextBuffer;
|
||||
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 dan200.computercraft.shared.util.Palette;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.RenderItem;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.client.ForgeHooksClient;
|
||||
import net.minecraftforge.client.event.RenderSpecificHandEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
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.gui.FixedWidthFontRenderer.*;
|
||||
import static dan200.computercraft.client.gui.GuiComputer.*;
|
||||
|
||||
/**
|
||||
* Emulates map rendering for pocket computers
|
||||
@ -38,6 +37,10 @@ import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
|
||||
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
|
||||
public final class ItemPocketRenderer extends ItemMapLikeRenderer
|
||||
{
|
||||
private static final int MARGIN = 2;
|
||||
private static final int FRAME = 12;
|
||||
private static final int LIGHT_HEIGHT = 8;
|
||||
|
||||
private static final ItemPocketRenderer INSTANCE = new ItemPocketRenderer();
|
||||
|
||||
private ItemPocketRenderer()
|
||||
@ -57,115 +60,194 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
|
||||
@Override
|
||||
protected void renderItem( ItemStack stack )
|
||||
{
|
||||
ClientComputer computer = ItemPocketComputer.createClientComputer( stack );
|
||||
Terminal terminal = computer == null ? null : computer.getTerminal();
|
||||
|
||||
int termWidth, termHeight;
|
||||
if( terminal == null )
|
||||
{
|
||||
termWidth = ComputerCraft.terminalWidth_pocketComputer;
|
||||
termHeight = ComputerCraft.terminalHeight_pocketComputer;
|
||||
}
|
||||
else
|
||||
{
|
||||
termWidth = terminal.getWidth();
|
||||
termHeight = terminal.getHeight();
|
||||
}
|
||||
|
||||
int width = termWidth * FONT_WIDTH + MARGIN * 2;
|
||||
int height = termHeight * FONT_HEIGHT + MARGIN * 2;
|
||||
|
||||
// Setup various transformations. Note that these are partially adapted from the corresponding method
|
||||
// in ItemRenderer
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
GlStateManager.disableLighting();
|
||||
GlStateManager.disableDepth();
|
||||
|
||||
GlStateManager.rotate( 180f, 0f, 1f, 0f );
|
||||
GlStateManager.rotate( 180f, 0f, 0f, 1f );
|
||||
GlStateManager.scale( 0.5, 0.5, 0.5 );
|
||||
|
||||
ClientComputer computer = ItemPocketComputer.createClientComputer( stack );
|
||||
double scale = 0.75 / Math.max( width + FRAME * 2, height + FRAME * 2 + LIGHT_HEIGHT );
|
||||
GlStateManager.scale( scale, scale, 0 );
|
||||
GlStateManager.translate( -0.5 * width, -0.5 * height, 0 );
|
||||
|
||||
// Render the main frame
|
||||
ComputerFamily family = ComputerCraft.Items.pocketComputer.getFamily( stack );
|
||||
int frameColour = ComputerCraft.Items.pocketComputer.getColour( stack );
|
||||
renderFrame( family, frameColour, width, height );
|
||||
|
||||
// Render the light
|
||||
int lightColour = ItemPocketComputer.getLightState( stack );
|
||||
if( lightColour == -1 ) lightColour = Colour.Black.getHex();
|
||||
renderLight( lightColour, width, height );
|
||||
|
||||
if( computer != null && terminal != null )
|
||||
{
|
||||
// First render the background item. We use the item's model rather than a direct texture as this ensures
|
||||
// we display the pocket light and other such decorations.
|
||||
GlStateManager.pushMatrix();
|
||||
// If we've a computer and terminal then attempt to render it.
|
||||
renderTerminal( terminal, !computer.isColour(), width, height );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise render a plain background
|
||||
Minecraft.getMinecraft().getTextureManager().bindTexture( BACKGROUND );
|
||||
|
||||
GlStateManager.scale( 1.0f, -1.0f, 1.0f );
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
|
||||
Minecraft minecraft = Minecraft.getMinecraft();
|
||||
TextureManager textureManager = minecraft.getTextureManager();
|
||||
RenderItem renderItem = minecraft.getRenderItem();
|
||||
|
||||
// Copy of RenderItem#renderItemModelIntoGUI but without the translation or scaling
|
||||
textureManager.bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE );
|
||||
textureManager.getTexture( TextureMap.LOCATION_BLOCKS_TEXTURE ).setBlurMipmap( false, false );
|
||||
|
||||
GlStateManager.enableRescaleNormal();
|
||||
GlStateManager.enableAlpha();
|
||||
GlStateManager.alphaFunc( GL11.GL_GREATER, 0.1F );
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.blendFunc( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA );
|
||||
GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F );
|
||||
|
||||
IBakedModel baked = renderItem.getItemModelWithOverrides( stack, null, null );
|
||||
baked = ForgeHooksClient.handleCameraTransforms( baked, ItemCameraTransforms.TransformType.GUI, false );
|
||||
renderItem.renderItem( stack, baked );
|
||||
|
||||
GlStateManager.disableAlpha();
|
||||
GlStateManager.disableRescaleNormal();
|
||||
Colour black = Colour.Black;
|
||||
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION );
|
||||
renderTexture( buffer, 0, 0, 0, 0, width, height, black.getR(), black.getG(), black.getB() );
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
GlStateManager.enableDepth();
|
||||
GlStateManager.enableLighting();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
// If we've a computer and terminal then attempt to render it.
|
||||
if( computer != null )
|
||||
private static void renderFrame( ComputerFamily family, int colour, int width, int height )
|
||||
{
|
||||
Terminal terminal = computer.getTerminal();
|
||||
if( terminal != null )
|
||||
|
||||
Minecraft.getMinecraft().getTextureManager().bindTexture( colour != -1
|
||||
? BACKGROUND_COLOUR
|
||||
: family == ComputerFamily.Normal ? BACKGROUND_NORMAL : BACKGROUND_ADVANCED
|
||||
);
|
||||
|
||||
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.getBuffer();
|
||||
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR );
|
||||
|
||||
// Top left, middle, right
|
||||
renderTexture( buffer, -FRAME, -FRAME, 12, 28, FRAME, FRAME, r, g, b );
|
||||
renderTexture( buffer, 0, -FRAME, 0, 0, width, FRAME, r, g, b );
|
||||
renderTexture( buffer, width, -FRAME, 24, 28, FRAME, FRAME, r, g, b );
|
||||
|
||||
// Left and bright border
|
||||
renderTexture( buffer, -FRAME, 0, 0, 28, FRAME, height, r, g, b );
|
||||
renderTexture( buffer, width, 0, 36, 28, FRAME, height, r, g, b );
|
||||
|
||||
// Bottom left, middle, right. We do this in three portions: the top inner corners, an extended region for
|
||||
// lights, and then the bottom outer corners.
|
||||
renderTexture( buffer, -FRAME, height, 12, 40, FRAME, FRAME / 2, r, g, b );
|
||||
renderTexture( buffer, 0, height, 0, 12, width, FRAME / 2, r, g, b );
|
||||
renderTexture( buffer, width, height, 24, 40, FRAME, FRAME / 2, r, g, b );
|
||||
|
||||
renderTexture( buffer, -FRAME, height + FRAME / 2, 12, 44, FRAME, LIGHT_HEIGHT, FRAME, 4, r, g, b );
|
||||
renderTexture( buffer, 0, height + FRAME / 2, 0, 16, width, LIGHT_HEIGHT, FRAME, 4, r, g, b );
|
||||
renderTexture( buffer, width, height + FRAME / 2, 24, 44, FRAME, LIGHT_HEIGHT, FRAME, 4, r, g, b );
|
||||
|
||||
renderTexture( buffer, -FRAME, height + LIGHT_HEIGHT + FRAME / 2, 12, 40 + FRAME / 2, FRAME, FRAME / 2, r, g, b );
|
||||
renderTexture( buffer, 0, height + LIGHT_HEIGHT + FRAME / 2, 0, 12 + FRAME / 2, width, FRAME / 2, r, g, b );
|
||||
renderTexture( buffer, width, height + LIGHT_HEIGHT + FRAME / 2, 24, 40 + FRAME / 2, FRAME, FRAME / 2, r, g, b );
|
||||
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
private static void renderLight( int colour, int width, int height )
|
||||
{
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.disableTexture2D();
|
||||
|
||||
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.getBuffer();
|
||||
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR );
|
||||
buffer.pos( width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex();
|
||||
buffer.pos( width, height + LIGHT_HEIGHT + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex();
|
||||
buffer.pos( width, height + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex();
|
||||
buffer.pos( width - LIGHT_HEIGHT * 2, height + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex();
|
||||
|
||||
tessellator.draw();
|
||||
GlStateManager.enableTexture2D();
|
||||
}
|
||||
|
||||
private static void renderTerminal( Terminal terminal, boolean greyscale, int width, int height )
|
||||
{
|
||||
synchronized( terminal )
|
||||
{
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.disableDepth();
|
||||
|
||||
// Reset the position to be at the top left corner of the pocket computer
|
||||
// Note we translate towards the screen slightly too.
|
||||
GlStateManager.translate( -8 / 16.0, -8 / 16.0, 0.5 / 16.0 );
|
||||
// Translate to the top left of the screen.
|
||||
GlStateManager.translate( 4 / 16.0, 3 / 16.0, 0 );
|
||||
|
||||
// Work out the scaling required to resize the terminal in order to fit on the computer
|
||||
final int margin = 2;
|
||||
int tw = terminal.getWidth();
|
||||
int th = terminal.getHeight();
|
||||
int width = tw * FONT_WIDTH + margin * 2;
|
||||
int height = th * FONT_HEIGHT + margin * 2;
|
||||
int max = Math.max( height, width );
|
||||
|
||||
// The grid is 8 * 8 wide, so we start with a base of 1/2 (8 / 16).
|
||||
double scale = 1.0 / 2.0 / max;
|
||||
GlStateManager.scale( scale, scale, scale );
|
||||
|
||||
// The margin/start positions are determined in order for the terminal to be centred.
|
||||
int startX = (max - width) / 2 + margin;
|
||||
int startY = (max - height) / 2 + margin;
|
||||
int termWidth = terminal.getWidth();
|
||||
int termHeight = terminal.getHeight();
|
||||
|
||||
FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance();
|
||||
boolean greyscale = !computer.isColour();
|
||||
Palette palette = terminal.getPalette();
|
||||
|
||||
// Render top/bottom borders
|
||||
TextBuffer emptyLine = new TextBuffer( ' ', termWidth );
|
||||
fontRenderer.drawString(
|
||||
emptyLine, MARGIN, 0,
|
||||
terminal.getTextColourLine( 0 ), terminal.getBackgroundColourLine( 0 ), MARGIN, MARGIN, greyscale, palette
|
||||
);
|
||||
fontRenderer.drawString(
|
||||
emptyLine, MARGIN, 2 * MARGIN + (termHeight - 1) * FixedWidthFontRenderer.FONT_HEIGHT,
|
||||
terminal.getTextColourLine( termHeight - 1 ), terminal.getBackgroundColourLine( termHeight - 1 ), MARGIN, MARGIN, greyscale, palette
|
||||
);
|
||||
|
||||
// Render the actual text
|
||||
for( int line = 0; line < th; line++ )
|
||||
for( int line = 0; line < termWidth; line++ )
|
||||
{
|
||||
TextBuffer text = terminal.getLine( line );
|
||||
TextBuffer colour = terminal.getTextColourLine( line );
|
||||
TextBuffer backgroundColour = terminal.getBackgroundColourLine( line );
|
||||
fontRenderer.drawString(
|
||||
text, startX, startY + line * FONT_HEIGHT,
|
||||
colour, backgroundColour, margin, margin, greyscale, palette
|
||||
text, MARGIN, MARGIN + line * FONT_HEIGHT,
|
||||
colour, backgroundColour, MARGIN, MARGIN, greyscale, palette
|
||||
);
|
||||
}
|
||||
|
||||
// And render the cursor;
|
||||
int tx = terminal.getCursorX(), ty = terminal.getCursorY();
|
||||
if( terminal.getCursorBlink() && FrameInfo.getGlobalCursorBlink() &&
|
||||
tx >= 0 && ty >= 0 && tx < tw && ty < th )
|
||||
tx >= 0 && ty >= 0 && tx < termWidth && ty < termHeight )
|
||||
{
|
||||
TextBuffer cursorColour = new TextBuffer( "0123456789abcdef".charAt( terminal.getTextColour() ), 1 );
|
||||
fontRenderer.drawString(
|
||||
new TextBuffer( '_', 1 ), startX + FONT_WIDTH * tx, startY + FONT_HEIGHT * ty,
|
||||
new TextBuffer( '_', 1 ), MARGIN + FONT_WIDTH * tx, MARGIN + FONT_HEIGHT * ty,
|
||||
cursorColour, null, 0, 0, greyscale, palette
|
||||
);
|
||||
}
|
||||
|
||||
GlStateManager.enableDepth();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GlStateManager.enableLighting();
|
||||
private static void renderTexture( BufferBuilder builder, int x, int y, int textureX, int textureY, int width, int height, float r, float g, float b )
|
||||
{
|
||||
renderTexture( builder, x, y, textureX, textureY, width, height, width, height, r, g, b );
|
||||
}
|
||||
|
||||
private static void renderTexture( BufferBuilder builder, int x, int y, int textureX, int textureY, int width, int height, int textureWidth, int textureHeight, float r, float g, float b )
|
||||
{
|
||||
float scale = 1 / 255.0f;
|
||||
builder.pos( x, y + height, 0 ).tex( textureX * scale, (textureY + textureHeight) * scale ).color( r, g, b, 1.0f ).endVertex();
|
||||
builder.pos( x + width, y + height, 0 ).tex( (textureX + textureWidth) * scale, (textureY + textureHeight) * scale ).color( r, g, b, 1.0f ).endVertex();
|
||||
builder.pos( x + width, y, 0 ).tex( (textureX + textureWidth) * scale, textureY * scale ).color( r, g, b, 1.0f ).endVertex();
|
||||
builder.pos( x, y, 0 ).tex( textureX * scale, textureY * scale ).color( r, g, b, 1.0f ).endVertex();
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
Loading…
Reference in New Issue
Block a user