|
| 1 | +package dan200.computercraft.client.render; |
| 2 | + |
| 3 | +import dan200.computercraft.ComputerCraft; |
| 4 | +import dan200.computercraft.client.gui.FixedWidthFontRenderer; |
| 5 | +import dan200.computercraft.client.gui.GuiPrintout; |
| 6 | +import dan200.computercraft.core.terminal.TextBuffer; |
| 7 | +import dan200.computercraft.shared.media.items.ItemPrintout; |
| 8 | +import dan200.computercraft.shared.util.Palette; |
| 9 | +import net.minecraft.client.Minecraft; |
| 10 | +import net.minecraft.client.renderer.BufferBuilder; |
| 11 | +import net.minecraft.client.renderer.GlStateManager; |
| 12 | +import net.minecraft.client.renderer.ItemRenderer; |
| 13 | +import net.minecraft.client.renderer.Tessellator; |
| 14 | +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; |
| 15 | +import net.minecraft.entity.player.EntityPlayer; |
| 16 | +import net.minecraft.item.ItemStack; |
| 17 | +import net.minecraft.util.EnumHand; |
| 18 | +import net.minecraft.util.EnumHandSide; |
| 19 | +import net.minecraft.util.math.MathHelper; |
| 20 | +import net.minecraftforge.client.event.RenderItemInFrameEvent; |
| 21 | +import net.minecraftforge.client.event.RenderSpecificHandEvent; |
| 22 | +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; |
| 23 | +import org.lwjgl.opengl.GL11; |
| 24 | + |
| 25 | +import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; |
| 26 | +import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH; |
| 27 | +import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAGE; |
| 28 | +import static dan200.computercraft.shared.media.items.ItemPrintout.LINE_MAX_LENGTH; |
| 29 | + |
| 30 | +public class ItemPrintoutRenderer |
| 31 | +{ |
| 32 | + @SubscribeEvent |
| 33 | + public void onRenderInHand( RenderSpecificHandEvent event ) |
| 34 | + { |
| 35 | + ItemStack stack = event.getItemStack(); |
| 36 | + if( stack.getItem() != ComputerCraft.Items.printout ) return; |
| 37 | + |
| 38 | + // We only allow single pages to be viewed in-hand for now |
| 39 | + if( ItemPrintout.getType( stack ) != ItemPrintout.Type.Single ) return; |
| 40 | + |
| 41 | + event.setCanceled( true ); |
| 42 | + |
| 43 | + EntityPlayer player = Minecraft.getMinecraft().player; |
| 44 | + |
| 45 | + GlStateManager.pushMatrix(); |
| 46 | + if( event.getHand() == EnumHand.MAIN_HAND && player.getHeldItemOffhand().isEmpty() ) |
| 47 | + { |
| 48 | + renderPrintoutFirstPersonCentre( |
| 49 | + event.getInterpolatedPitch(), |
| 50 | + event.getEquipProgress(), |
| 51 | + event.getSwingProgress(), |
| 52 | + stack |
| 53 | + ); |
| 54 | + } |
| 55 | + else |
| 56 | + { |
| 57 | + renderPrintoutFirstPersonSide( |
| 58 | + event.getHand() == EnumHand.MAIN_HAND ? player.getPrimaryHand() : player.getPrimaryHand().opposite(), |
| 59 | + event.getEquipProgress(), |
| 60 | + event.getSwingProgress(), |
| 61 | + stack |
| 62 | + ); |
| 63 | + } |
| 64 | + GlStateManager.popMatrix(); |
| 65 | + } |
| 66 | + |
| 67 | + /** |
| 68 | + * Renders a pocket computer to one side of the player. |
| 69 | + * |
| 70 | + * @param side The side to render on |
| 71 | + * @param equipProgress The equip progress of this item |
| 72 | + * @param swingProgress The swing progress of this item |
| 73 | + * @param stack The stack to render |
| 74 | + * @see ItemRenderer#renderMapFirstPersonSide(float, EnumHandSide, float, ItemStack) |
| 75 | + */ |
| 76 | + private void renderPrintoutFirstPersonSide( EnumHandSide side, float equipProgress, float swingProgress, ItemStack stack ) |
| 77 | + { |
| 78 | + Minecraft minecraft = Minecraft.getMinecraft(); |
| 79 | + float offset = side == EnumHandSide.RIGHT ? 1f : -1f; |
| 80 | + GlStateManager.translate( offset * 0.125f, -0.125f, 0f ); |
| 81 | + |
| 82 | + // If the player is not invisible then render a single arm |
| 83 | + if( !minecraft.player.isInvisible() ) |
| 84 | + { |
| 85 | + GlStateManager.pushMatrix(); |
| 86 | + GlStateManager.rotate( offset * 10f, 0f, 0f, 1f ); |
| 87 | + minecraft.getItemRenderer().renderArmFirstPerson( equipProgress, swingProgress, side ); |
| 88 | + GlStateManager.popMatrix(); |
| 89 | + } |
| 90 | + |
| 91 | + // Setup the appropriate transformations. This is just copied from the |
| 92 | + // corresponding method in ItemRenderer. |
| 93 | + GlStateManager.pushMatrix(); |
| 94 | + GlStateManager.translate( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f ); |
| 95 | + float f1 = MathHelper.sqrt( swingProgress ); |
| 96 | + float f2 = MathHelper.sin( f1 * (float) Math.PI ); |
| 97 | + float f3 = -0.5f * f2; |
| 98 | + float f4 = 0.4f * MathHelper.sin( f1 * ((float) Math.PI * 2f) ); |
| 99 | + float f5 = -0.3f * MathHelper.sin( swingProgress * (float) Math.PI ); |
| 100 | + GlStateManager.translate( offset * f3, f4 - 0.3f * f2, f5 ); |
| 101 | + GlStateManager.rotate( f2 * -45f, 1f, 0f, 0f ); |
| 102 | + GlStateManager.rotate( offset * f2 * -30f, 0f, 1f, 0f ); |
| 103 | + |
| 104 | + renderPrintoutFirstPerson( stack ); |
| 105 | + |
| 106 | + GlStateManager.popMatrix(); |
| 107 | + } |
| 108 | + |
| 109 | + /** |
| 110 | + * Render an item in the middle of the screen |
| 111 | + * |
| 112 | + * @param pitch The pitch of the player |
| 113 | + * @param equipProgress The equip progress of this item |
| 114 | + * @param swingProgress The swing progress of this item |
| 115 | + * @param stack The stack to render |
| 116 | + * @see ItemRenderer#renderMapFirstPerson(float, float, float) |
| 117 | + */ |
| 118 | + private void renderPrintoutFirstPersonCentre( float pitch, float equipProgress, float swingProgress, ItemStack stack ) |
| 119 | + { |
| 120 | + ItemRenderer itemRenderer = Minecraft.getMinecraft().getItemRenderer(); |
| 121 | + |
| 122 | + // Setup the appropriate transformations. This is just copied from the |
| 123 | + // corresponding method in ItemRenderer. |
| 124 | + float swingRt = MathHelper.sqrt( swingProgress ); |
| 125 | + float tX = -0.2f * MathHelper.sin( swingProgress * (float) Math.PI ); |
| 126 | + float tZ = -0.4f * MathHelper.sin( swingRt * (float) Math.PI ); |
| 127 | + GlStateManager.translate( 0f, -tX / 2f, tZ ); |
| 128 | + float pitchAngle = itemRenderer.getMapAngleFromPitch( pitch ); |
| 129 | + GlStateManager.translate( 0f, 0.04f + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f ); |
| 130 | + GlStateManager.rotate( pitchAngle * -85f, 1f, 0f, 0f ); |
| 131 | + itemRenderer.renderArms(); |
| 132 | + float rX = MathHelper.sin( swingRt * (float) Math.PI ); |
| 133 | + GlStateManager.rotate( rX * 20f, 1f, 0f, 0f ); |
| 134 | + GlStateManager.scale( 2f, 2f, 2f ); |
| 135 | + |
| 136 | + renderPrintoutFirstPerson( stack ); |
| 137 | + } |
| 138 | + |
| 139 | + |
| 140 | + private static void renderPrintoutFirstPerson( ItemStack stack ) |
| 141 | + { |
| 142 | + // Setup various transformations. Note that these are partially adapated from the corresponding method |
| 143 | + // in ItemRenderer.renderMapFirstPerson |
| 144 | + GlStateManager.disableLighting(); |
| 145 | + |
| 146 | + GlStateManager.rotate( 180f, 0f, 1f, 0f ); |
| 147 | + GlStateManager.rotate( 180f, 0f, 0f, 1f ); |
| 148 | + GlStateManager.scale( 0.38f, 0.38f, 0.38f ); |
| 149 | + GlStateManager.translate( -0.5f, -0.5f, 0.0f ); |
| 150 | + |
| 151 | + drawPrintout( stack ); |
| 152 | + |
| 153 | + GlStateManager.enableLighting(); |
| 154 | + } |
| 155 | + |
| 156 | + @SubscribeEvent |
| 157 | + public void onRenderInFrame( RenderItemInFrameEvent event ) |
| 158 | + { |
| 159 | + ItemStack stack = event.getItem(); |
| 160 | + if( stack.getItem() != ComputerCraft.Items.printout ) return; |
| 161 | + |
| 162 | + // We only allow single pages to be viewed in-hand for now |
| 163 | + if( ItemPrintout.getType( stack ) != ItemPrintout.Type.Single ) return; |
| 164 | + |
| 165 | + event.setCanceled( true ); |
| 166 | + |
| 167 | + GlStateManager.disableLighting(); |
| 168 | + |
| 169 | + // Move a little bit forward to ensure we're not clipping with the frame |
| 170 | + GlStateManager.translate( 0.0f, 0.0f, -0.001f ); |
| 171 | + GlStateManager.rotate( 180f, 0f, 0f, 1f ); |
| 172 | + GlStateManager.translate( -0.5f, -0.5f, 0.0f ); |
| 173 | + |
| 174 | + drawPrintout( stack ); |
| 175 | + |
| 176 | + GlStateManager.enableLighting(); |
| 177 | + } |
| 178 | + |
| 179 | + private static void drawPrintout( ItemStack stack ) |
| 180 | + { |
| 181 | + int xMargin = 13; |
| 182 | + int yMargin = 11; |
| 183 | + |
| 184 | + int width = LINE_MAX_LENGTH * FONT_WIDTH + xMargin * 2; |
| 185 | + int height = LINES_PER_PAGE * FONT_HEIGHT + yMargin * 2; |
| 186 | + int max = Math.max( height, width ); |
| 187 | + |
| 188 | + // Scale the printout to fit correctly. |
| 189 | + double scale = 1.0 / max; |
| 190 | + GlStateManager.scale( scale, scale, scale ); |
| 191 | + GlStateManager.translate( (max - width) / 2.0f, (max - height) / 2.0f, 0.0f ); |
| 192 | + |
| 193 | + drawBackground( 0, 0, 0.01 ); |
| 194 | + |
| 195 | + FixedWidthFontRenderer fontRenderer = (FixedWidthFontRenderer) ComputerCraft.getFixedWidthFontRenderer(); |
| 196 | + |
| 197 | + String[] text = ItemPrintout.getText( stack ); |
| 198 | + String[] colours = ItemPrintout.getColours( stack ); |
| 199 | + for( int line = 0; line < LINES_PER_PAGE && line < text.length; ++line ) |
| 200 | + { |
| 201 | + fontRenderer.drawString( new TextBuffer( text[ line ] ), xMargin, yMargin + line * FONT_HEIGHT, new TextBuffer( colours[ line ] ), null, 0, 0, false, Palette.DEFAULT ); |
| 202 | + } |
| 203 | + } |
| 204 | + |
| 205 | + private static void drawBackground( double x, double y, double z ) |
| 206 | + { |
| 207 | + Minecraft mc = Minecraft.getMinecraft(); |
| 208 | + mc.getTextureManager().bindTexture( GuiPrintout.BACKGROUND ); |
| 209 | + |
| 210 | + Tessellator tessellator = Tessellator.getInstance(); |
| 211 | + BufferBuilder buffer = tessellator.getBuffer(); |
| 212 | + buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX ); |
| 213 | + buffer.pos( x, y + GuiPrintout.Y_SIZE, z ).tex( 24 / 256.0, GuiPrintout.Y_SIZE / 256.0 ).endVertex(); |
| 214 | + buffer.pos( x + GuiPrintout.X_SIZE, y + GuiPrintout.Y_SIZE, z ).tex( (24 + GuiPrintout.X_SIZE) / 256.0, GuiPrintout.Y_SIZE / 256.0 ).endVertex(); |
| 215 | + buffer.pos( x + GuiPrintout.X_SIZE, y, z ).tex( (24 + GuiPrintout.X_SIZE) / 256.0, 0 ).endVertex(); |
| 216 | + buffer.pos( x, y, z ).tex( 24 / 256.0, 0 ).endVertex(); |
| 217 | + tessellator.draw(); |
| 218 | + } |
| 219 | +} |
0 commit comments