From 50797bb99c6a747be9de5ac1025a798366d90960 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 6 Jul 2018 23:35:01 +0100 Subject: [PATCH] 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 )); + } +}