Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fancy rendering of printouts #553

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add basic support for fancy rendering of printouts
 - When held in first-person, single pages are displayed like a map.
 - When placed in an item frame, the page is drawn instead of the actual
   item.
SquidDev committed Jun 18, 2018

Verified

This commit was signed with the committer’s verified signature.
commit c0bdd4ff1dad41988ce2d51cfdb9e38fc68aca59
47 changes: 23 additions & 24 deletions src/main/java/dan200/computercraft/client/gui/GuiPrintout.java
Original file line number Diff line number Diff line change
@@ -20,10 +20,9 @@

public class GuiPrintout extends GuiContainer
{
private static final ResourceLocation background = new ResourceLocation( "computercraft", "textures/gui/printout.png" );

private static final int xSize = 172;
private static final int ySize = 209;
public static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/printout.png" );
public static final int X_SIZE = 172;
public static final int Y_SIZE = 209;

private final boolean m_book;
private final int m_pages;
@@ -142,57 +141,57 @@ public void drawScreen(int mouseX, int mouseY, float f)

// Draw the printout
GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f );
this.mc.getTextureManager().bindTexture( background );
this.mc.getTextureManager().bindTexture( BACKGROUND );

int startY = (height - ySize) / 2;
//int startX = (width - xSize) / 2 - (m_page * 8);
int startX = (width - (xSize + (m_pages - 1)*8)) / 2;
int startY = (height - Y_SIZE) / 2;
//int startX = (width - X_SIZE) / 2 - (m_page * 8);
int startX = (width - (X_SIZE + (m_pages - 1)*8)) / 2;

if( m_book )
{
// Border
drawTexturedModalRect( startX - 8, startY - 8, xSize + 48, 0, 12, ySize + 24);
drawTexturedModalRect( startX + xSize + (m_pages - 1)*8 - 4, startY - 8, xSize + 48 + 12, 0, 12, ySize + 24);
drawTexturedModalRect( startX - 8, startY - 8, X_SIZE + 48, 0, 12, Y_SIZE + 24);
drawTexturedModalRect( startX + X_SIZE + (m_pages - 1)*8 - 4, startY - 8, X_SIZE + 48 + 12, 0, 12, Y_SIZE + 24);

drawTexturedModalRect( startX, startY - 8, 0, ySize, xSize, 12);
drawTexturedModalRect( startX, startY + ySize - 4, 0, ySize + 12, xSize, 12);
drawTexturedModalRect( startX, startY - 8, 0, Y_SIZE, X_SIZE, 12);
drawTexturedModalRect( startX, startY + Y_SIZE - 4, 0, Y_SIZE + 12, X_SIZE, 12);
for( int n=1; n<m_pages; ++n )
{
drawTexturedModalRect( startX + xSize + (n-1)*8, startY - 8, 0, ySize, 8, 12);
drawTexturedModalRect( startX + xSize + (n-1)*8, startY + ySize - 4, 0, ySize + 12, 8, 12);
drawTexturedModalRect( startX + X_SIZE + (n-1)*8, startY - 8, 0, Y_SIZE, 8, 12);
drawTexturedModalRect( startX + X_SIZE + (n-1)*8, startY + Y_SIZE - 4, 0, Y_SIZE + 12, 8, 12);
}
}

// Left half
if( m_page == 0 )
{
drawTexturedModalRect( startX, startY, 24, 0, xSize / 2, ySize);
drawTexturedModalRect( startX, startY, 0, 0, 12, ySize);
drawTexturedModalRect( startX, startY, 24, 0, X_SIZE / 2, Y_SIZE );
drawTexturedModalRect( startX, startY, 0, 0, 12, Y_SIZE );
}
else
{
drawTexturedModalRect( startX, startY, 0, 0, 12, ySize);
drawTexturedModalRect( startX, startY, 0, 0, 12, Y_SIZE );
for( int n=1; n<m_page; ++n )
{
drawTexturedModalRect( startX + n*8, startY, 12, 0, 12, ySize);
drawTexturedModalRect( startX + n*8, startY, 12, 0, 12, Y_SIZE );
}
drawTexturedModalRect( startX + m_page*8, startY, 24, 0, xSize / 2, ySize);
drawTexturedModalRect( startX + m_page*8, startY, 24, 0, X_SIZE / 2, Y_SIZE );
}

// Right half
if( m_page == (m_pages - 1) )
{
drawTexturedModalRect( startX + m_page*8 + xSize/2, startY, 24 + xSize / 2, 0, xSize / 2, ySize);
drawTexturedModalRect( startX + m_page*8 + (xSize - 12), startY, 24 + xSize + 12, 0, 12, ySize);
drawTexturedModalRect( startX + m_page*8 + X_SIZE /2, startY, 24 + X_SIZE / 2, 0, X_SIZE / 2, Y_SIZE );
drawTexturedModalRect( startX + m_page*8 + (X_SIZE - 12), startY, 24 + X_SIZE + 12, 0, 12, Y_SIZE );
}
else
{
drawTexturedModalRect( startX + (m_pages - 1)*8 + (xSize - 12), startY, 24 + xSize + 12, 0, 12, ySize);
drawTexturedModalRect( startX + (m_pages - 1)*8 + (X_SIZE - 12), startY, 24 + X_SIZE + 12, 0, 12, Y_SIZE );
for( int n=m_pages-2; n>=m_page; --n )
{
drawTexturedModalRect( startX + n*8 + (xSize - 12), startY, 24 + xSize, 0, 12, ySize);
drawTexturedModalRect( startX + n*8 + (X_SIZE - 12), startY, 24 + X_SIZE, 0, 12, Y_SIZE );
}
drawTexturedModalRect( startX + m_page*8 + xSize/2, startY, 24 + xSize / 2, 0, xSize / 2, ySize);
drawTexturedModalRect( startX + m_page*8 + X_SIZE /2, startY, 24 + X_SIZE / 2, 0, X_SIZE / 2, Y_SIZE );
}

// Draw the text
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@

import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.*;
import dan200.computercraft.client.render.ItemPrintoutRenderer;
import dan200.computercraft.client.render.TileEntityMonitorRenderer;
import dan200.computercraft.shared.computer.blocks.ComputerState;
import dan200.computercraft.shared.computer.blocks.TileComputer;
@@ -442,6 +443,7 @@ private void registerForgeHandlers()
{
ForgeHandlers handlers = new ForgeHandlers();
MinecraftForge.EVENT_BUS.register( handlers );
MinecraftForge.EVENT_BUS.register( new ItemPrintoutRenderer() );
}

public class ForgeHandlers
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
package dan200.computercraft.client.render;

import dan200.computercraft.ComputerCraft;
import dan200.computercraft.client.gui.FixedWidthFontRenderer;
import dan200.computercraft.client.gui.GuiPrintout;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.media.items.ItemPrintout;
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.ItemRenderer;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumHandSide;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.client.event.RenderItemInFrameEvent;
import net.minecraftforge.client.event.RenderSpecificHandEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
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.shared.media.items.ItemPrintout.LINES_PER_PAGE;
import static dan200.computercraft.shared.media.items.ItemPrintout.LINE_MAX_LENGTH;

public class ItemPrintoutRenderer
{
@SubscribeEvent
public void onRenderInHand( RenderSpecificHandEvent event )
{
ItemStack stack = event.getItemStack();
if( stack.getItem() != ComputerCraft.Items.printout ) return;

// We only allow single pages to be viewed in-hand for now
if( ItemPrintout.getType( stack ) != ItemPrintout.Type.Single ) return;

event.setCanceled( true );

EntityPlayer player = Minecraft.getMinecraft().player;

GlStateManager.pushMatrix();
if( event.getHand() == EnumHand.MAIN_HAND && player.getHeldItemOffhand().isEmpty() )
{
renderPrintoutFirstPersonCentre(
event.getInterpolatedPitch(),
event.getEquipProgress(),
event.getSwingProgress(),
stack
);
}
else
{
renderPrintoutFirstPersonSide(
event.getHand() == EnumHand.MAIN_HAND ? player.getPrimaryHand() : player.getPrimaryHand().opposite(),
event.getEquipProgress(),
event.getSwingProgress(),
stack
);
}
GlStateManager.popMatrix();
}

/**
* Renders a pocket computer to one side of the player.
*
* @param side The side to render on
* @param equipProgress The equip progress of this item
* @param swingProgress The swing progress of this item
* @param stack The stack to render
* @see ItemRenderer#renderMapFirstPersonSide(float, EnumHandSide, float, ItemStack)
*/
private void renderPrintoutFirstPersonSide( EnumHandSide side, float equipProgress, float swingProgress, ItemStack stack )
{
Minecraft minecraft = Minecraft.getMinecraft();
float offset = side == EnumHandSide.RIGHT ? 1f : -1f;
GlStateManager.translate( offset * 0.125f, -0.125f, 0f );

// If the player is not invisible then render a single arm
if( !minecraft.player.isInvisible() )
{
GlStateManager.pushMatrix();
GlStateManager.rotate( offset * 10f, 0f, 0f, 1f );
minecraft.getItemRenderer().renderArmFirstPerson( equipProgress, swingProgress, side );
GlStateManager.popMatrix();
}

// Setup the appropriate transformations. This is just copied from the
// corresponding method in ItemRenderer.
GlStateManager.pushMatrix();
GlStateManager.translate( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f );
float f1 = MathHelper.sqrt( swingProgress );
float f2 = MathHelper.sin( f1 * (float) Math.PI );
float f3 = -0.5f * f2;
float f4 = 0.4f * MathHelper.sin( f1 * ((float) Math.PI * 2f) );
float f5 = -0.3f * MathHelper.sin( swingProgress * (float) Math.PI );
GlStateManager.translate( offset * f3, f4 - 0.3f * f2, f5 );
GlStateManager.rotate( f2 * -45f, 1f, 0f, 0f );
GlStateManager.rotate( offset * f2 * -30f, 0f, 1f, 0f );

renderPrintoutFirstPerson( stack );

GlStateManager.popMatrix();
}

/**
* Render an item in the middle of the screen
*
* @param pitch The pitch of the player
* @param equipProgress The equip progress of this item
* @param swingProgress The swing progress of this item
* @param stack The stack to render
* @see ItemRenderer#renderMapFirstPerson(float, float, float)
*/
private void renderPrintoutFirstPersonCentre( float pitch, float equipProgress, float swingProgress, ItemStack stack )
{
ItemRenderer itemRenderer = Minecraft.getMinecraft().getItemRenderer();

// Setup the appropriate transformations. This is just copied from the
// corresponding method in ItemRenderer.
float swingRt = MathHelper.sqrt( swingProgress );
float tX = -0.2f * MathHelper.sin( swingProgress * (float) Math.PI );
float tZ = -0.4f * MathHelper.sin( swingRt * (float) Math.PI );
GlStateManager.translate( 0f, -tX / 2f, tZ );
float pitchAngle = itemRenderer.getMapAngleFromPitch( pitch );
GlStateManager.translate( 0f, 0.04f + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f );
GlStateManager.rotate( pitchAngle * -85f, 1f, 0f, 0f );
itemRenderer.renderArms();
float rX = MathHelper.sin( swingRt * (float) Math.PI );
GlStateManager.rotate( rX * 20f, 1f, 0f, 0f );
GlStateManager.scale( 2f, 2f, 2f );

renderPrintoutFirstPerson( stack );
}


private static void renderPrintoutFirstPerson( ItemStack stack )
{
// Setup various transformations. Note that these are partially adapated from the corresponding method
// in ItemRenderer.renderMapFirstPerson
GlStateManager.disableLighting();

GlStateManager.rotate( 180f, 0f, 1f, 0f );
GlStateManager.rotate( 180f, 0f, 0f, 1f );
GlStateManager.scale( 0.38f, 0.38f, 0.38f );
GlStateManager.translate( -0.5f, -0.5f, 0.0f );

drawPrintout( stack );

GlStateManager.enableLighting();
}

@SubscribeEvent
public void onRenderInFrame( RenderItemInFrameEvent event )
{
ItemStack stack = event.getItem();
if( stack.getItem() != ComputerCraft.Items.printout ) return;

// We only allow single pages to be viewed in-hand for now
if( ItemPrintout.getType( stack ) != ItemPrintout.Type.Single ) return;

event.setCanceled( true );

GlStateManager.disableLighting();

// Move a little bit forward to ensure we're not clipping with the frame
GlStateManager.translate( 0.0f, 0.0f, -0.001f );
GlStateManager.rotate( 180f, 0f, 0f, 1f );
GlStateManager.translate( -0.5f, -0.5f, 0.0f );

drawPrintout( stack );

GlStateManager.enableLighting();
}

private static void drawPrintout( ItemStack stack )
{
int xMargin = 13;
int yMargin = 11;

int width = LINE_MAX_LENGTH * FONT_WIDTH + xMargin * 2;
int height = LINES_PER_PAGE * FONT_HEIGHT + yMargin * 2;
int max = Math.max( height, width );

// Scale the printout to fit correctly.
double scale = 1.0 / max;
GlStateManager.scale( scale, scale, scale );
GlStateManager.translate( (max - width) / 2.0f, (max - height) / 2.0f, 0.0f );

drawBackground( 0, 0, 0.01 );

FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer) ComputerCraft.getFixedWidthFontRenderer();

String[] text = ItemPrintout.getText( stack );
String[] colours = ItemPrintout.getColours( stack );
for( int line = 0; line < LINES_PER_PAGE && line < text.length; ++line )
{
fontRenderer.drawString( new TextBuffer( text[ line ] ), xMargin, yMargin + line * FONT_HEIGHT, new TextBuffer( colours[ line ] ), null, 0, 0, false, Palette.DEFAULT );
}
}

private static void drawBackground( double x, double y, double z )
{
Minecraft mc = Minecraft.getMinecraft();
mc.getTextureManager().bindTexture( GuiPrintout.BACKGROUND );

Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX );
buffer.pos( x, y + GuiPrintout.Y_SIZE, z ).tex( 24 / 256.0, GuiPrintout.Y_SIZE / 256.0 ).endVertex();
buffer.pos( x + GuiPrintout.X_SIZE, y + GuiPrintout.Y_SIZE, z ).tex( (24 + GuiPrintout.X_SIZE) / 256.0, GuiPrintout.Y_SIZE / 256.0 ).endVertex();
buffer.pos( x + GuiPrintout.X_SIZE, y, z ).tex( (24 + GuiPrintout.X_SIZE) / 256.0, 0 ).endVertex();
buffer.pos( x, y, z ).tex( 24 / 256.0, 0 ).endVertex();
tessellator.draw();
}
}
4 changes: 4 additions & 0 deletions src/main/resources/META-INF/computercraft_at.cfg
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# RecordMedia (and related methods)
public net.minecraft.item.ItemRecord field_185076_b # sound
public net.minecraft.item.ItemRecord field_185077_c # displayName
# ItemPocketRenderer
public net.minecraft.client.renderer.ItemRenderer func_187466_c()V # renderArms
public net.minecraft.client.renderer.ItemRenderer func_178100_c(F)F # getMapAngleFromPitch
public net.minecraft.client.renderer.ItemRenderer func_187456_a(FFLnet/minecraft/util/EnumHandSide;)V # renderArmFirstPerson