package sourcecoded.quantum.client.gui; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.entity.RenderItem; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.ShapedRecipes; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.ResourceLocation; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.GL11; import sourcecoded.quantum.Constants; import sourcecoded.quantum.api.CraftingContext; import sourcecoded.quantum.api.arrangement.IArrangementRecipe; import sourcecoded.quantum.api.arrangement.ItemMatrix; import sourcecoded.quantum.api.block.Colourizer; import sourcecoded.quantum.api.discovery.DiscoveryItem; import sourcecoded.quantum.api.discovery.DiscoveryPage; import sourcecoded.quantum.api.discovery.DiscoveryRegistry; import sourcecoded.quantum.api.injection.IInjectorRecipe; import sourcecoded.quantum.api.translation.LocalizationUtils; import sourcecoded.quantum.api.vacuum.IVacuumRecipe; import sourcecoded.quantum.registry.QABlocks; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static org.lwjgl.opengl.GL11.*; public class GuiDiscoveryPage extends GuiScreen { public static ResourceLocation pageLocation = new ResourceLocation(Constants.MODID, "textures/gui/book.png"); public static ResourceLocation guiBlank = new ResourceLocation(Constants.MODID, "textures/misc/blank.png"); int frameWidth = 146; int frameHeight = 180; int pageIndex = 0; int mx; int my; DiscoveryItem parentItem; DiscoveryPage currentPage; GuiDiscoveryCategory parentGui; EntityPlayer player; boolean mouse = true; public GuiDiscoveryPage(DiscoveryItem item, int page, EntityPlayer player, GuiDiscoveryCategory categoryGUI) { this.pageIndex = page; this.parentItem = item; this.currentPage = item.getPages().get(pageIndex); this.player = player; this.parentGui = categoryGUI; if (parentGui == null) parentGui = new GuiDiscoveryCategory(DiscoveryRegistry.getCategoryForItem(item.getKey()), player); } public void keyTyped(char Char, int par2) { if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE) || Keyboard.isKeyDown(Keyboard.KEY_E)) { if (isShiftKeyDown()) this.mc.displayGuiScreen(null); else this.mc.displayGuiScreen(parentGui); } } public boolean doesGuiPauseGame() { return false; } public void drawScreen(int mx, int my, float par3) { int centreW = super.width / 2; int centreH = super.height / 2; this.mx = mx; this.my = my; Tessellator tess = Tessellator.instance; this.mc.getTextureManager().bindTexture(pageLocation); this.drawTexturedModalRect(centreW - frameWidth / 2, centreH - frameHeight / 2 - 10, 20, 1, frameWidth, frameHeight); String titleText = "Discovery"; if (currentPage.title != null) titleText = currentPage.localizeTitle(); float scale = 0.8F; float scaleI = (float) Math.pow(scale, -1); int itemY = centreH - 78; GL11.glTranslatef(centreW, itemY, 0); GL11.glScalef(scale, scale, scale); drawCenteredStringWOShadow(fontRendererObj, titleText, 0, 0, Colourizer.BLACK.toInteger()); GL11.glScalef(scaleI, scaleI, scaleI); GL11.glTranslatef(-centreW, -itemY, 0); GL11.glColor4f(1F, 1F, 1F, 1F); int buttonY = centreH + frameHeight / 2 - 20; int buttonSizeX = 18; int buttonSizeY = 11; int buttonBack = centreW - frameWidth / 2 + 10; int buttonForward = centreW + frameWidth / 2 - 30; this.mc.getTextureManager().bindTexture(pageLocation); if (this.parentItem.pages.size() > pageIndex + 1) { if (mx >= buttonForward && mx <= buttonForward + buttonSizeX && my >= buttonY && my <= buttonY + buttonSizeY) { this.drawTexturedModalRect(buttonForward, buttonY, 26, 194, buttonSizeX, buttonSizeY); if (Mouse.isButtonDown(0) && !mouse) this.mc.displayGuiScreen(new GuiDiscoveryPage(this.parentItem, pageIndex + 1, player, parentGui)); } else this.drawTexturedModalRect(buttonForward, buttonY, 3, 194, buttonSizeX, buttonSizeY); } if (this.pageIndex > 0) { if (mx >= buttonBack && mx <= buttonBack + buttonSizeX && my >= buttonY && my <= buttonY + buttonSizeY) { this.drawTexturedModalRect(buttonBack, buttonY, 26, 207, buttonSizeX, buttonSizeY); if (Mouse.isButtonDown(0) && !mouse) this.mc.displayGuiScreen(new GuiDiscoveryPage(this.parentItem, pageIndex - 1, player, parentGui)); } else this.drawTexturedModalRect(buttonBack, buttonY, 3, 207, buttonSizeX, buttonSizeY); } switch (currentPage.type) { case TEXT: renderText(centreH - 67); break; case IMAGE: renderImagePage(); break; case CRAFTING: renderCrafting(false); break; case ARRANGEMENT: renderCrafting(true); break; case INJECTION: renderInjection(); break; case VACUUM: renderVacuum(); break; } renderTooltips(); mouse = Mouse.isButtonDown(0); } public void renderText(int y) { int centreW = super.width / 2; int pad = 20; FontRenderer renderer = this.fontRendererObj; boolean shouldDoUnicode = fontRendererObj.getUnicodeFlag(); renderer.setUnicodeFlag(true); //Makes sure text-scaling isn't an issue String textEntry = currentPage.localizeText(); textEntry = textEntry.replace("<br>", "\n\n"); //Line Breaks renderer.FONT_HEIGHT--; renderer.drawSplitString(textEntry, centreW - frameWidth / 2 + pad, y, frameWidth - pad * 2, Colourizer.BLACK.toInteger()); renderer.FONT_HEIGHT++; renderer.setUnicodeFlag(shouldDoUnicode); //Reset unicode } public void renderImagePage() { int centreW = super.width / 2; int centreH = super.height / 2; int pad = 20; this.mc.getTextureManager().bindTexture(this.currentPage.image); int imgH = glGetTexLevelParameteri(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT); int imgW = glGetTexLevelParameteri(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH); float ratio = imgH / (float)imgW; int width = frameWidth - pad * 2; this.drawFullQuadWithBounds(centreW - frameWidth / 2 + pad, centreH - 60, width, (int) (width * ratio)); renderText(centreH + 20); } public void renderCrafting(boolean arrangement) { int centreW = super.width / 2; int centreH = super.height / 2; RenderItem render = new RenderItem(); this.mc.getTextureManager().bindTexture(pageLocation); GL11.glAlphaFunc(GL11.GL_GREATER, 0F); GL11.glColor4f(1F, 1F, 1F, 0.07F); this.drawTexturedModalRect(centreW - 30, centreH - 50, 46, 186, 61, 61); GL11.glColor4f(1F, 1F, 1F, 1F); String table = LocalizationUtils.escapeFormatting(QABlocks.ARRANGEMENT.getBlock().getLocalizedName()); if (!arrangement) table = Blocks.crafting_table.getLocalizedName(); float scale = 0.5F; float scaleI = (float) Math.pow(scale, -1); GL11.glTranslatef(centreW, centreH - 65, 0); GL11.glScalef(scale, scale, scale); drawCenteredStringWOShadow(fontRendererObj, EnumChatFormatting.ITALIC + table, 0, 0, Colourizer.BLACK.toInteger()); GL11.glScalef(scaleI, scaleI, scaleI); GL11.glTranslatef(-centreW, -centreH + 65, 0); ItemMatrix matrix; ItemStack output; if (arrangement) { IArrangementRecipe recipe = (IArrangementRecipe) currentPage.recipe; matrix = recipe.getMatrix(); output = recipe.getOutput(); } else { matrix = ItemMatrix.createFromRecipe((ShapedRecipes) currentPage.recipe); output = ((IRecipe)currentPage.recipe).getRecipeOutput(); } int xStart = centreW - 30; int xPadding = 22; int yStart = centreH - 49; int yPadding = 22; if (output != null) { this.mc.getTextureManager().bindTexture(pageLocation); GL11.glColor4f(1F, 1F, 1F, 0.2F); drawPartialQuadWithBounds(centreW - 4, centreH + 16, 10, 14, 5/256F, 220/256F, 13/256F, 231/256F); renderItemAndOverlay(render, fontRendererObj, this.mc.getTextureManager(), output, centreW - 7, centreH + 32, true); } if (matrix != null) { for (int i = 0; i < matrix.getWidth(); i++) for (int j = 0; j < matrix.getHeight(); j++) { ItemStack stack = matrix.getItemAt(j, i); //Why is this backwards? Idk, I screwed something up. Oh well, idc if (stack == null) continue; renderItemAndOverlay(render, fontRendererObj, this.mc.getTextureManager(), stack, xStart + xPadding * i, yStart + yPadding * j, true); GL11.glColor4f(1F, 1F, 1F, 1F); GL11.glDisable(GL11.GL_LIGHTING); } } this.mc.getTextureManager().bindTexture(pageLocation); if (arrangement) { IArrangementRecipe recipe = (IArrangementRecipe) currentPage.recipe; renderCraftingContext(recipe.getContext()); } else { GL11.glEnable(GL11.GL_BLEND); RenderHelper.disableStandardItemLighting(); GL11.glColor4f(1F, 1F, 1F, 0.4F); renderVanillaRecipe(centreW + 45, centreH + 28, mx, my); GL11.glEnable(GL11.GL_BLEND); RenderHelper.disableStandardItemLighting(); } } public void renderInjection() { int centreW = super.width / 2; int centreH = super.height / 2; RenderItem render = new RenderItem(); float scale = 0.5F; float scaleI = (float) Math.pow(scale, -1); GL11.glTranslatef(centreW, centreH - 65, 0); GL11.glScalef(scale, scale, scale); drawCenteredStringWOShadow(fontRendererObj, EnumChatFormatting.ITALIC + LocalizationUtils.escapeFormatting(QABlocks.RIFT_INJECTION_POOL.getBlock().getLocalizedName()), 0, 0, Colourizer.BLACK.toInteger()); GL11.glScalef(scaleI, scaleI, scaleI); GL11.glTranslatef(-centreW, -centreH + 65, 0); this.mc.getTextureManager().bindTexture(pageLocation); GL11.glAlphaFunc(GL11.GL_GREATER, 0F); GL11.glColor4f(1F, 1F, 1F, 0.2F); drawPartialQuadWithBounds(centreW - 26, centreH - 40, 14, 10, 28 / 256F, 222 / 256F, 39 / 256F, 230 / 256F); drawPartialQuadWithBounds(centreW + 11, centreH - 40, 14, 10, 28 / 256F, 222 / 256F, 39 / 256F, 230 / 256F); render.renderItemAndEffectIntoGUI(fontRendererObj, mc.getTextureManager(), new ItemStack(QABlocks.RIFT_INJECTION_POOL.getBlock()), centreW - 8, centreH - 44); IInjectorRecipe recipe = (IInjectorRecipe) currentPage.recipe; DecimalFormat format = new DecimalFormat("#,##0"); if (recipe != null) { GL11.glTranslatef(centreW, centreH - 25, 0); GL11.glScalef(scale, scale, scale); drawCenteredStringWOShadow(fontRendererObj, format.format(recipe.getEnergyRequired()) + " QRE", 0, 0, Colourizer.BLACK.toInteger()); drawCenteredStringWOShadow(fontRendererObj, "Tier: " + recipe.getTier(), 0, 13, Colourizer.BLACK.toInteger()); GL11.glScalef(scaleI, scaleI, scaleI); GL11.glTranslatef(-centreW, -centreH + 25, 0); renderItemAndOverlay(render, fontRendererObj, mc.getTextureManager(), recipe.getInput(), centreW - 44, centreH - 44, true); renderItemAndOverlay(render, fontRendererObj, mc.getTextureManager(), recipe.getOutput(), centreW + 28, centreH - 44, true); renderCraftingContext(recipe.getContext()); } } public void renderVacuum() { int centreW = super.width / 2; int centreH = super.height / 2; RenderItem render = new RenderItem(); float scale = 0.5F; float scaleI = (float) Math.pow(scale, -1); GL11.glTranslatef(centreW, centreH - 65, 0); GL11.glScalef(scale, scale, scale); String translation = "qa.vacuum.chamber.name"; drawCenteredStringWOShadow(fontRendererObj, EnumChatFormatting.ITALIC + LocalizationUtils.escapeFormatting(LocalizationUtils.translateLocalWithColours(translation, translation)), 0, 0, Colourizer.BLACK.toInteger()); GL11.glScalef(scaleI, scaleI, scaleI); GL11.glTranslatef(-centreW, -centreH + 65, 0); GL11.glAlphaFunc(GL11.GL_GREATER, 0F); GL11.glColor4f(1F, 1F, 1F, 0.11F); this.mc.getTextureManager().bindTexture(pageLocation); drawPartialQuadWithBounds(centreW - 47, centreH - 50, 100, 100, 118 / 256F, 193 / 256F, 168 / 256F, 243 / 256F); GL11.glColor4f(1F, 1F, 1F, 1F); IVacuumRecipe recipe = (IVacuumRecipe) currentPage.recipe; DecimalFormat format = new DecimalFormat("#,##0"); if (recipe != null) { GL11.glTranslatef(centreW, centreH + 50, 0); GL11.glScalef(scale, scale, scale); drawCenteredStringWOShadow(fontRendererObj, format.format(recipe.getVacuumEnergyStart()) + " QRE (Start)", 0, 0, Colourizer.BLACK.toInteger()); drawCenteredStringWOShadow(fontRendererObj, format.format(recipe.getVacuumEnergyPerItem()) + " QRE (Per Item)", 0, 13, Colourizer.BLACK.toInteger()); drawCenteredStringWOShadow(fontRendererObj, "Instability: " + recipe.getInstabilityLevel().getInstabilityName(), 0, 26, Colourizer.BLACK.toInteger()); GL11.glScalef(scaleI, scaleI, scaleI); GL11.glTranslatef(-centreW, -centreH - 50, 0); GL11.glTranslatef(centreW, centreH - 50, 0); GL11.glScalef(scale, scale, scale); drawCenteredStringWOShadow(fontRendererObj, "Catalysts", 0, 0, Colourizer.BLACK.toInteger()); drawCenteredStringWOShadow(fontRendererObj, "Inputs", 0, 60, Colourizer.BLACK.toInteger()); drawCenteredStringWOShadow(fontRendererObj, "Outputs", 0, 130, Colourizer.BLACK.toInteger()); GL11.glScalef(scaleI, scaleI, scaleI); GL11.glTranslatef(-centreW, -centreH + 50, 0); int perOffsetX = 20; int perOffsetY = 16; List<List<ItemStack>> inputs = splitStackList(recipe.getIngredients()); List<List<ItemStack>> catalysts = splitStackList(recipe.getCatalysts()); List<List<ItemStack>> output = splitStackList(recipe.getOutputs()); float itemScale = 0.8F; float itemScaleI = (float) Math.pow(itemScale, -1); int nmx = mx - centreW; int nmy = my - centreH; GL11.glTranslatef(centreW, centreH, 0); GL11.glScalef(itemScale, itemScale, itemScale); makeMaartenHappy(inputs, perOffsetX, perOffsetY, itemScale, nmx, nmy, 26); makeMaartenHappy(catalysts, perOffsetX, perOffsetY, itemScale, nmx, nmy, -11); makeMaartenHappy(output, perOffsetX, perOffsetY, itemScale, nmx, nmy, 71); GL11.glScalef(itemScaleI, itemScaleI, itemScaleI); GL11.glTranslatef(-centreW, -centreH, 0); renderCraftingContext(recipe.getContext()); } } //It's a long story public void makeMaartenHappy(List<List<ItemStack>> lists, int perOffsetX, int perOffsetY, float itemScale, int nmx, int nmy, int yIndex) { for (List<ItemStack> stackList : lists) { int totalOffset = perOffsetX * (stackList.size() + 1); int yOffset = perOffsetY * lists.indexOf(stackList) + yIndex; for (ItemStack stack : stackList) { int xFactor = perOffsetX * (stackList.indexOf(stack) + 1); xFactor -= (totalOffset / 2); int itemX = - 8 + xFactor; int itemY = - 8 - 38 + yOffset; renderItemAndOverlay(itemRender, fontRendererObj, mc.getTextureManager(), stack, itemX, itemY, false); if (nmx >= itemX*itemScale && nmx <= itemX*itemScale+itemScale*16 && nmy >= itemY*itemScale && nmy <=itemY*itemScale+itemScale*16) { this.tooltip(stack.getTooltip(player, true), mx, my); } } } } public List<List<ItemStack>> splitStackList(List<ItemStack> stacks) { List<List<ItemStack>> list = new ArrayList<List<ItemStack>>(); int index = 0; int level = 0; for (ItemStack stack : stacks) { if (index == 7) { level++; index = 0; } if (list.size() == level || list.get(level) == null) list.add(new ArrayList<ItemStack>()); list.get(level).add(stack); index++; } return list; } public void renderCraftingContext(CraftingContext context) { int centreW = super.width / 2; int centreH = super.height / 2; GL11.glEnable(GL11.GL_BLEND); RenderHelper.disableStandardItemLighting(); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); if (context.oreDictionary) { GL11.glColor4f(1F, 1F, 1F, 0.4F); renderOreDictionary(centreW + 45, centreH + 28, mx, my); GL11.glEnable(GL11.GL_BLEND); RenderHelper.disableStandardItemLighting(); } if (context.respectsMeta) { GL11.glColor4f(1F, 1F, 1F, 0.4F); renderRespectDamage(centreW + 45, centreH + 40, mx, my); GL11.glEnable(GL11.GL_BLEND); RenderHelper.disableStandardItemLighting(); } if (context.respectsNBT) { GL11.glColor4f(1F, 1F, 1F, 0.4F); renderRespectNBT(centreW + 45, centreH + 52, mx, my); GL11.glEnable(GL11.GL_BLEND); RenderHelper.disableStandardItemLighting(); } } public void renderOreDictionary(int x, int y, int mx, int my) { this.mc.getTextureManager().bindTexture(pageLocation); int texU = 177; int texV = 189; drawPartialQuadWithBounds(x, y, 10, 10, texU/256F, texV/256F, (texU+16F)/256F, (texV+16F)/256F); if (mx >= x && mx <= x+10 && my >= y && my <=y+10) { String[] tooltip = new String[] {"qa.journal.gui.oredict.title", "qa.journal.gui.oredict"}; this.tooltip(LocalizationUtils.translateList(Arrays.asList(tooltip)), mx, my); } } public void renderRespectDamage(int x, int y, int mx, int my) { this.mc.getTextureManager().bindTexture(pageLocation); int texU = 194; int texV = 189; drawPartialQuadWithBounds(x, y, 10, 10, texU/256F, texV/256F, (texU+16F)/256F, (texV+16F)/256F); if (mx >= x && mx <= x+10 && my >= y && my <=y+10) { String[] tooltip = new String[] {"qa.journal.gui.damage.title", "qa.journal.gui.damage"}; this.tooltip(LocalizationUtils.translateList(Arrays.asList(tooltip)), mx, my); } } public void renderRespectNBT(int x, int y, int mx, int my) { this.mc.getTextureManager().bindTexture(pageLocation); int texU = 210; int texV = 189; drawPartialQuadWithBounds(x, y, 10, 10, texU/256F, texV/256F, (texU+16F)/256F, (texV+16F)/256F); if (mx >= x && mx <= x+10 && my >= y && my <=y+10) { String[] tooltip = new String[] {"qa.journal.gui.nbt.title", "qa.journal.gui.nbt"}; this.tooltip(LocalizationUtils.translateList(Arrays.asList(tooltip)), mx, my); } } public void renderVanillaRecipe(int x, int y, int mx, int my) { this.mc.getTextureManager().bindTexture(pageLocation); int texU = 227; int texV = 188; drawPartialQuadWithBounds(x, y, 10, 10, texU/256F, texV/256F, (texU+16F)/256F, (texV+16F)/256F); if (mx >= x && mx <= x+10 && my >= y && my <=y+10) { String[] tooltip = new String[] {"qa.journal.gui.vanilla.title", "qa.journal.gui.vanilla"}; this.tooltip(LocalizationUtils.translateList(Arrays.asList(tooltip)), mx, my); } } public void renderItemAndOverlay(RenderItem render, FontRenderer f, TextureManager tex, ItemStack stack, int x, int y, boolean tooltip) { RenderHelper.disableStandardItemLighting(); render.renderItemAndEffectIntoGUI(f, tex, stack, x, y); render.renderItemOverlayIntoGUI(f, tex, stack, x, y); if (tooltip && mx >= x && mx <= x+16 && my >= y && my <=y+16) { this.tooltip(stack.getTooltip(player, true), mx, my); } } List<Tooltip> tips = new ArrayList<Tooltip>(); public void tooltip(List text, int x, int y) { tips.add(new Tooltip(text, x, y)); } public void renderTooltips() { for (Tooltip tip : tips) { this.drawHoveringText(tip.text, tip.x, tip.y, fontRendererObj); } tips.clear(); } public void drawCenteredStringWOShadow(FontRenderer fontRenderer, String string, int x, int y, int colour) { fontRenderer.drawString(string, x - fontRenderer.getStringWidth(string) / 2, y, colour); } public void drawFullQuadWithBounds(int x, int y, int width, int height) { Tessellator tess = Tessellator.instance; tess.startDrawingQuads(); tess.addVertexWithUV(x, y + height, this.zLevel, 0, 1); tess.addVertexWithUV(x + width, y + height, this.zLevel, 1, 1); tess.addVertexWithUV(x + width, y, this.zLevel, 1, 0); tess.addVertexWithUV(x, y, this.zLevel, 0, 0); tess.draw(); } public void drawPartialQuadWithBounds(int x, int y, int width, int height, float u, float v, float U, float V) { Tessellator tess = Tessellator.instance; tess.startDrawingQuads(); tess.addVertexWithUV(x, y + height, this.zLevel, u, V); tess.addVertexWithUV(x + width, y + height, this.zLevel, U, V); tess.addVertexWithUV(x + width, y, this.zLevel, U, v); tess.addVertexWithUV(x, y, this.zLevel, u, v); tess.draw(); } }