From c0bdd4ff1dad41988ce2d51cfdb9e38fc68aca59 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 18 Jun 2018 22:09:24 +0100 Subject: [PATCH 1/3] 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. --- .../computercraft/client/gui/GuiPrintout.java | 47 ++-- .../proxy/ComputerCraftProxyClient.java | 2 + .../client/render/ItemPrintoutRenderer.java | 219 ++++++++++++++++++ .../resources/META-INF/computercraft_at.cfg | 4 + 4 files changed, 248 insertions(+), 24 deletions(-) create mode 100644 src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java index 06d994150e..f37a57a822 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java @@ -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_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 diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java index db2da93303..0c554f3670 100644 --- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java +++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java @@ -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 diff --git a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java new file mode 100644 index 0000000000..c4703f63ff --- /dev/null +++ b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java @@ -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(); + } +} diff --git a/src/main/resources/META-INF/computercraft_at.cfg b/src/main/resources/META-INF/computercraft_at.cfg index 48f245c203..e25cd87c64 100644 --- a/src/main/resources/META-INF/computercraft_at.cfg +++ b/src/main/resources/META-INF/computercraft_at.cfg @@ -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 From 50797bb99c6a747be9de5ac1025a798366d90960 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 6 Jul 2018 23:35:01 +0100 Subject: [PATCH 2/3] Rewrite printout rendering - The current page is always centred when rendering in a GUI, with the turned pages moving from the sides. - Pages are no longer evenly distributed from the centre - they follow an exponential decay curve, so ones further out are closer together (a bit like an open book). - Render pages and books in item frames/in-hand (rather than just single pages). This currently does some very dirty things with z values in order to prevent z-fighting. It would be nice to avoid that, though turning off writing to the z buffer causes issues with the bounding box. --- .../computercraft/client/gui/GuiPrintout.java | 126 +++----------- .../client/render/ItemPrintoutRenderer.java | 70 +++----- .../client/render/PrintoutRenderer.java | 162 ++++++++++++++++++ 3 files changed, 209 insertions(+), 149 deletions(-) create mode 100644 src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java index f37a57a822..b297fbcc96 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java @@ -6,24 +6,19 @@ package dan200.computercraft.client.gui; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.media.inventory.ContainerHeldItem; import dan200.computercraft.shared.media.items.ItemPrintout; -import dan200.computercraft.shared.util.Palette; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.util.ResourceLocation; import org.lwjgl.input.Mouse; import java.io.IOException; +import static dan200.computercraft.client.render.PrintoutRenderer.*; + public class GuiPrintout extends GuiContainer { - 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; private final TextBuffer[] m_text; @@ -33,23 +28,18 @@ public class GuiPrintout extends GuiContainer public GuiPrintout( ContainerHeldItem container ) { super( container ); - m_book = (ItemPrintout.getType( container.getStack() ) == ItemPrintout.Type.Book); String[] text = ItemPrintout.getText( container.getStack() ); m_text = new TextBuffer[ text.length ]; - for( int i=0; i 0 ) - { - m_page = m_page - 1; - } + // Left + if( m_page > 0 ) m_page--; } } @@ -105,21 +89,15 @@ public void handleMouseInput() throws IOException super.handleMouseInput(); int mouseWheelChange = Mouse.getEventDWheel(); - if (mouseWheelChange < 0) + if( mouseWheelChange < 0 ) { // Up - if( m_page < m_pages - 1 ) - { - m_page = m_page + 1; - } + if( m_page < m_pages - 1 ) m_page++; } - else if (mouseWheelChange > 0) + else if( mouseWheelChange > 0 ) { // Down - if( m_page > 0 ) - { - m_page = m_page - 1; - } + if( m_page > 0 ) m_page--; } } @@ -134,78 +112,20 @@ protected void drawGuiContainerBackgroundLayer( float var1, int var2, int var3 ) } @Override - public void drawScreen(int mouseX, int mouseY, float f) + public void drawScreen( int mouseX, int mouseY, float f ) { // Draw background + zLevel = zLevel - 1; drawDefaultBackground(); - + zLevel = zLevel + 1; + // Draw the printout GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f ); - this.mc.getTextureManager().bindTexture( BACKGROUND ); - + 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, 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, Y_SIZE, X_SIZE, 12); - drawTexturedModalRect( startX, startY + Y_SIZE - 4, 0, Y_SIZE + 12, X_SIZE, 12); - for( int n=1; n=m_page; --n ) - { - drawTexturedModalRect( startX + n*8 + (X_SIZE - 12), startY, 24 + X_SIZE, 0, 12, Y_SIZE ); - } - drawTexturedModalRect( startX + m_page*8 + X_SIZE /2, startY, 24 + X_SIZE / 2, 0, X_SIZE / 2, Y_SIZE ); - } + int startX = (width - X_SIZE) / 2; - // Draw the text - FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer)ComputerCraft.getFixedWidthFontRenderer(); - int x = startX + m_page * 8 + 13; - int y = startY + 11; - for( int line=0; line= 0 && lineIdx < m_text.length ) - { - fontRenderer.drawString( m_text[lineIdx], x, y, m_colours[lineIdx], null, 0, 0, false, Palette.DEFAULT ); - } - y = y + FixedWidthFontRenderer.FONT_HEIGHT; - } + drawBorder( startX, startY, zLevel, m_page, m_pages, m_book ); + drawText( startX + X_TEXT_MARGIN, startY + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * m_page, m_text, m_colours ); } } diff --git a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java index c4703f63ff..e3812a6121 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java @@ -1,17 +1,10 @@ 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; @@ -20,10 +13,10 @@ 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.client.render.PrintoutRenderer.*; import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE; import static dan200.computercraft.shared.media.items.ItemPrintout.LINE_MAX_LENGTH; @@ -35,9 +28,6 @@ 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; @@ -145,8 +135,8 @@ private static void renderPrintoutFirstPerson( ItemStack stack ) 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 ); + GlStateManager.scale( 0.42f, 0.42f, -0.42f ); + GlStateManager.translate( -0.5f, -0.48f, 0.0f ); drawPrintout( stack ); @@ -159,9 +149,6 @@ 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(); @@ -169,6 +156,7 @@ public void onRenderInFrame( RenderItemInFrameEvent event ) // 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.scale( 0.95f, 0.95f, -0.95f ); GlStateManager.translate( -0.5f, -0.5f, 0.0f ); drawPrintout( stack ); @@ -178,42 +166,32 @@ public void onRenderInFrame( RenderItemInFrameEvent event ) 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 ); + int pages = ItemPrintout.getPageCount( stack ); + boolean book = ItemPrintout.getType( stack ) == ItemPrintout.Type.Book; - // 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 ); + double width = LINE_MAX_LENGTH * FONT_WIDTH + X_TEXT_MARGIN * 2; + double height = LINES_PER_PAGE * FONT_HEIGHT + Y_TEXT_MARGIN * 2; - drawBackground( 0, 0, 0.01 ); + // Non-books will be left aligned + if( !book ) width += offsetAt( pages ); - FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer) ComputerCraft.getFixedWidthFontRenderer(); + double visualWidth = width, visualHeight = height; - String[] text = ItemPrintout.getText( stack ); - String[] colours = ItemPrintout.getColours( stack ); - for( int line = 0; line < LINES_PER_PAGE && line < text.length; ++line ) + // Meanwhile books will be centred + if( book ) { - fontRenderer.drawString( new TextBuffer( text[ line ] ), xMargin, yMargin + line * FONT_HEIGHT, new TextBuffer( colours[ line ] ), null, 0, 0, false, Palette.DEFAULT ); + visualWidth += 2 * COVER_SIZE + 2 * offsetAt( pages ); + visualHeight += 2 * COVER_SIZE; } - } - 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(); + double max = Math.max( visualHeight, visualWidth ); + + // 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 ); + + drawBorder( 0, 0, -0.01, 0, pages, book ); + drawText( X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) ); } } diff --git a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java new file mode 100644 index 0000000000..64e3888c6a --- /dev/null +++ b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java @@ -0,0 +1,162 @@ +package dan200.computercraft.client.render; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.client.gui.FixedWidthFontRenderer; +import dan200.computercraft.core.terminal.TextBuffer; +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.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; + +import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; +import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE; + +public class PrintoutRenderer +{ + private static final ResourceLocation BG = new ResourceLocation( "computercraft", "textures/gui/printout.png" ); + private static final double BG_SIZE = 256.0; + + /** + * Width of a page + */ + public static final int X_SIZE = 172; + + /** + * Height of a page + */ + public static final int Y_SIZE = 209; + + /** + * Padding between the left and right of a page and the text + */ + public static final int X_TEXT_MARGIN = 13; + + /** + * Padding between the top and bottom of a page and the text + */ + public static final int Y_TEXT_MARGIN = 11; + + /** + * Width of the extra page texture + */ + private static final int X_FOLD_SIZE = 12; + + /** + * Size of the leather cover + */ + public static final int COVER_SIZE = 12; + + private static final int COVER_Y = Y_SIZE; + private static final int COVER_X = X_SIZE + 4 * X_FOLD_SIZE; + + public static void drawText( int x, int y, int start, TextBuffer[] text, TextBuffer[] colours ) + { + FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer) ComputerCraft.getFixedWidthFontRenderer(); + + for( int line = 0; line < LINES_PER_PAGE && line < text.length; ++line ) + { + fontRenderer.drawString( text[ start + line ], x, y + line * FONT_HEIGHT, colours[ start + line ], null, 0, 0, false, Palette.DEFAULT ); + } + } + + public static void drawText( int x, int y, int start, String[] text, String[] colours ) + { + FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer) ComputerCraft.getFixedWidthFontRenderer(); + + for( int line = 0; line < LINES_PER_PAGE && line < text.length; ++line ) + { + fontRenderer.drawString( new TextBuffer( text[ start + line ] ), x, y + line * FONT_HEIGHT, new TextBuffer( colours[ start + line ] ), null, 0, 0, false, Palette.DEFAULT ); + } + } + + public static void drawBorder( double x, double y, double z, int page, int pages, boolean isBook ) + { + GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f ); + Minecraft.getMinecraft().getTextureManager().bindTexture( BG ); + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX ); + + int leftPages = page; + int rightPages = pages - page - 1; + + if( isBook ) + { + // Border + double offset = offsetAt( pages ); + final double left = x - 4 - offset; + final double right = x + X_SIZE + offset - 4; + + // Left and right border + drawTexture( buffer, left - 4, y - 8, z - 0.02, COVER_X, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 ); + drawTexture( buffer, right, y - 8, z - 0.02, COVER_X + COVER_SIZE, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 ); + + // Draw centre panel (just stretched texture, sorry). + drawTexture( buffer, + x - offset, y, z - 0.02, X_SIZE + offset * 2, Y_SIZE, + COVER_X + COVER_SIZE / 2, COVER_SIZE, COVER_SIZE, Y_SIZE + ); + + double borderX = left; + while( borderX < right ) + { + double thisWidth = Math.min( right - borderX, X_SIZE ); + drawTexture( buffer, borderX, y - 8, z - 0.02, 0, COVER_Y, thisWidth, COVER_SIZE ); + drawTexture( buffer, borderX, y + Y_SIZE - 4, z - 0.02, 0, COVER_Y + COVER_SIZE, thisWidth, COVER_SIZE ); + borderX += thisWidth; + } + } + + // Left half + drawTexture( buffer, x, y, z, X_FOLD_SIZE * 2, 0, X_SIZE / 2, Y_SIZE ); + for( int n = 0; n <= leftPages; n++ ) + { + drawTexture( buffer, + x - offsetAt( n ), y, z - 1e-3 * n, + // Use the left "bold" fold for the outermost page + n == leftPages ? 0 : X_FOLD_SIZE, 0, + X_FOLD_SIZE, Y_SIZE + ); + } + + // Right half + drawTexture( buffer, x + X_SIZE / 2, y, z, X_FOLD_SIZE * 2 + X_SIZE / 2, 0, X_SIZE / 2, Y_SIZE ); + for( int n = 0; n <= rightPages; n++ ) + { + drawTexture( buffer, + x + (X_SIZE - X_FOLD_SIZE) + offsetAt( n ), y, z - 1e-3 * 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 + ); + } + + tessellator.draw(); + } + + private static void drawTexture( BufferBuilder buffer, double x, double y, double z, double u, double v, double width, double height ) + { + buffer.pos( x, y + height, z ).tex( u / BG_SIZE, (v + height) / BG_SIZE ).endVertex(); + buffer.pos( x + width, y + height, z ).tex( (u + width) / BG_SIZE, (v + height) / BG_SIZE ).endVertex(); + buffer.pos( x + width, y, z ).tex( (u + width) / BG_SIZE, v / BG_SIZE ).endVertex(); + buffer.pos( x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex(); + } + + private static void drawTexture( BufferBuilder buffer, double x, double y, double z, double width, double height, double u, double v, double tWidth, double tHeight ) + { + buffer.pos( x, y + height, z ).tex( u / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex(); + buffer.pos( x + width, y + height, z ).tex( (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex(); + buffer.pos( x + width, y, z ).tex( (u + tWidth) / BG_SIZE, v / BG_SIZE ).endVertex(); + buffer.pos( x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex(); + } + + public static double offsetAt( int page ) + { + return 32 * (1 - Math.pow( 1.2, -page )); + } +} From 64d9c33916a15e76e23064fb6e501b5a40059c65 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 13 Aug 2018 22:25:58 +0100 Subject: [PATCH 3/3] Reset a few more flags when rendering printouts Closes #63 --- .../computercraft/client/render/PrintoutRenderer.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java index 64e3888c6a..da5e8ddb4e 100644 --- a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java @@ -65,6 +65,10 @@ public static void drawText( int x, int y, int start, TextBuffer[] text, TextBuf public static void drawText( int x, int y, int start, String[] text, String[] colours ) { + GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f ); + GlStateManager.enableBlend(); + GlStateManager.enableTexture2D(); + FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer) ComputerCraft.getFixedWidthFontRenderer(); for( int line = 0; line < LINES_PER_PAGE && line < text.length; ++line ) @@ -76,6 +80,9 @@ public static void drawText( int x, int y, int start, String[] text, String[] co public static void drawBorder( double x, double y, double z, int page, int pages, boolean isBook ) { GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f ); + GlStateManager.enableBlend(); + GlStateManager.enableTexture2D(); + Minecraft.getMinecraft().getTextureManager().bindTexture( BG ); Tessellator tessellator = Tessellator.getInstance();