package codechicken.nei.config; import codechicken.core.CommonUtils; import codechicken.lib.gui.GuiDraw; import codechicken.nei.ItemPanel; import codechicken.nei.NEIClientConfig; import codechicken.nei.NEIClientUtils; import codechicken.nei.guihook.GuiContainerManager; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.texture.TextureUtil; import net.minecraft.client.shader.Framebuffer; import net.minecraft.item.ItemStack; import net.minecraft.util.ChatComponentTranslation; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.IChatComponent; import org.lwjgl.BufferUtils; import org.lwjgl.input.Keyboard; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.nio.IntBuffer; import java.util.Arrays; public class GuiItemIconDumper extends GuiScreen { final static int[] illegalChars = { 34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47 }; static { Arrays.sort(illegalChars); } private Option opt; private int drawIndex; private int parseIndex; private File dir = new File(CommonUtils.getMinecraftDir(), "dumps/itempanel_icons"); private int iconSize; private int borderSize; private int boxSize; public GuiItemIconDumper(Option opt, int iconSize) { this.opt = opt; this.iconSize = iconSize; borderSize = iconSize / 16; boxSize = iconSize + borderSize * 2; if (dir.exists()) { for (File f : dir.listFiles()) { if (f.isFile()) { f.delete(); } } } else { dir.mkdirs(); } } private void returnScreen(IChatComponent msg) { Minecraft.getMinecraft().displayGuiScreen(opt.slot.getGui()); NEIClientUtils.printChatMessage(msg); } @Override protected void keyTyped(char c, int keycode) throws IOException { if (keycode == Keyboard.KEY_ESCAPE || keycode == Keyboard.KEY_BACK) { returnScreen(new ChatComponentTranslation(opt.fullName() + ".icon.cancelled")); return; } super.keyTyped(c, keycode); } @Override public void drawScreen(int mousex, int mousey, float frame) { try { drawItems(); exportItems(); } catch (Exception e) { NEIClientConfig.logger.error("Error dumping item icons", e); } } private void drawItems() { Dimension d = GuiDraw.displayRes(); GlStateManager.matrixMode(GL11.GL_PROJECTION); GlStateManager.loadIdentity(); GlStateManager.ortho(0, d.width * 16D / iconSize, d.height * 16D / iconSize, 0, 1000, 3000); GlStateManager.matrixMode(GL11.GL_MODELVIEW); GlStateManager.clearColor(0, 0, 0, 0); GlStateManager.clear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); int rows = d.height / boxSize; int cols = d.width / boxSize; int fit = rows * cols; RenderHelper.enableGUIStandardItemLighting(); GlStateManager.enableRescaleNormal(); GlStateManager.color(1, 1, 1, 1); for (int i = 0; drawIndex < ItemPanel.items.size() && i < fit; drawIndex++, i++) { int x = i % cols * 18; int y = i / cols * 18; GuiContainerManager.drawItem(x + 1, y + 1, ItemPanel.items.get(drawIndex)); } GL11.glFlush(); } private void exportItems() throws IOException { BufferedImage img = screenshot(); int rows = img.getHeight() / boxSize; int cols = img.getWidth() / boxSize; int fit = rows * cols; for (int i = 0; parseIndex < ItemPanel.items.size() && i < fit; parseIndex++, i++) { int x = i % cols * boxSize; int y = i / cols * boxSize; exportImage(dir, img.getSubimage(x + borderSize, y + borderSize, iconSize, iconSize), ItemPanel.items.get(parseIndex)); } if (parseIndex >= ItemPanel.items.size()) { returnScreen(new ChatComponentTranslation(opt.fullName() + ".icon.dumped", "dumps/itempanel_icons")); } } public static String cleanFileName(String name) { StringBuilder cleanName = new StringBuilder(); for (int i = 0; i < name.length(); i++) { int c = (int) name.charAt(i); if (Arrays.binarySearch(illegalChars, c) < 0) { cleanName.append((char) c); } else { cleanName.append('_'); } } return cleanName.toString(); } private void exportImage(File dir, BufferedImage img, ItemStack stack) throws IOException { String name = EnumChatFormatting.getTextWithoutFormattingCodes(GuiContainerManager.itemDisplayNameShort(stack)); name = cleanFileName(name); File file = new File(dir, name + ".png"); for (int i = 2; file.exists(); i++) { file = new File(dir, name + '_' + i + ".png"); } ImageIO.write(img, "png", file); } private IntBuffer pixelBuffer; private int[] pixelValues; private BufferedImage screenshot() { Framebuffer fb = Minecraft.getMinecraft().getFramebuffer(); Dimension mcSize = GuiDraw.displayRes(); Dimension texSize = mcSize; if (OpenGlHelper.isFramebufferEnabled()) { texSize = new Dimension(fb.framebufferTextureWidth, fb.framebufferTextureHeight); } int k = texSize.width * texSize.height; if (pixelBuffer == null || pixelBuffer.capacity() < k) { pixelBuffer = BufferUtils.createIntBuffer(k); pixelValues = new int[k]; } GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1); GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1); pixelBuffer.clear(); if (OpenGlHelper.isFramebufferEnabled()) { GlStateManager.bindTexture(fb.framebufferTexture); GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, pixelBuffer); } else { GL11.glReadPixels(0, 0, texSize.width, texSize.height, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, pixelBuffer); } pixelBuffer.get(pixelValues); TextureUtil.processPixelValues(pixelValues, texSize.width, texSize.height); BufferedImage img = new BufferedImage(mcSize.width, mcSize.height, BufferedImage.TYPE_INT_ARGB); if (OpenGlHelper.isFramebufferEnabled()) { int yOff = texSize.height - mcSize.height; for (int y = 0; y < mcSize.height; ++y) { for (int x = 0; x < mcSize.width; ++x) { img.setRGB(x, y, pixelValues[(y + yOff) * texSize.width + x]); } } } else { img.setRGB(0, 0, texSize.width, height, pixelValues, 0, texSize.width); } return img; } }