package advancedsystemsmanager.client.gui.fonts; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL12; import java.awt.*; import java.awt.image.BufferedImage; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import static org.lwjgl.opengl.GL11.*; @SideOnly(Side.CLIENT) public class FontRenderer { private CharData[] charArray = new CharData[256]; private Map<Character, CharData> customChars = new HashMap<Character, CharData>(); private boolean antiAlias; private int fontSize = 0; private int fontHeight = 0; private int textureID = Integer.MIN_VALUE; private int textureWidth = 512; private int textureHeight = 512; private Font font; private float zLevel; public FontRenderer(Font font, boolean antiAlias) { this(font, antiAlias, null); } public FontRenderer(Font font, boolean antiAlias, char[] additionalChars) { this.font = font; this.fontSize = font.getSize(); this.antiAlias = antiAlias; loadFont(additionalChars); } private void loadFont(char[] customCharsArray) { if (customCharsArray != null && customCharsArray.length > 0) { textureWidth *= 2; } BufferedImage imgTemp = new BufferedImage(textureWidth, textureHeight, BufferedImage.TYPE_INT_ARGB); Graphics2D g = (Graphics2D)imgTemp.getGraphics(); g.setColor(new Color(255, 255, 255, 0)); g.fillRect(0, 0, textureWidth, textureHeight); int rowHeight = 0; int positionX = 0; int positionY = 0; if (customCharsArray == null) customCharsArray = new char[0]; int customCharsLength = customCharsArray.length; for (int i = 0; i < 256 + customCharsLength; i++) { char ch = (i < 256) ? (char)i : customCharsArray[i - 256]; BufferedImage fontImage = getFontImage(ch); CharData newCharData = new CharData(); newCharData.width = fontImage.getWidth(); newCharData.height = fontImage.getHeight(); if (positionX + newCharData.width >= textureWidth) { positionX = 0; positionY += rowHeight + 1; rowHeight = 0; } newCharData.storedX = positionX; newCharData.storedY = positionY; if (newCharData.height > fontHeight) { fontHeight = newCharData.height; } if (newCharData.height > rowHeight) { rowHeight = newCharData.height; } g.drawImage(fontImage, positionX, positionY, null); positionX += newCharData.width + 1; if (i < 256) { charArray[i] = newCharData; } else { customChars.put(ch, newCharData); } fontImage = null; } // try // { // // ImageIO.write(imgTemp, "PNG", new File("test.png")); // } catch (IOException e) // { // e.printStackTrace(); // } textureID = loadTexture(imgTemp, textureID); } private BufferedImage getFontImage(char ch) { BufferedImage tempFontImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); Graphics2D g = (Graphics2D)tempFontImage.getGraphics(); if (antiAlias) { g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } g.setFont(font); FontMetrics fontMetrics = g.getFontMetrics(); int charWidth = fontMetrics.charWidth(ch); if (charWidth <= 0) { charWidth = 1; } int charHeight = fontMetrics.getHeight(); if (charHeight <= 0) { charHeight = fontSize; } BufferedImage fontImage = new BufferedImage(charWidth, charHeight, BufferedImage.TYPE_INT_ARGB); Graphics2D gt = (Graphics2D)fontImage.getGraphics(); if (antiAlias) { gt.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } gt.setFont(font); gt.setColor(Color.WHITE); int charX = 0; int charY = 0; gt.drawString(String.valueOf(ch), (charX), (charY) + fontMetrics.getAscent()); return fontImage; } public int loadTexture(BufferedImage image, int textureID) { int[] pixels = new int[image.getWidth() * image.getHeight()]; image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth()); ByteBuffer buffer = BufferUtils.createByteBuffer(image.getWidth() * image.getHeight() * 4); for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { int pixel = pixels[y * image.getWidth() + x]; buffer.put((byte)((pixel >> 16) & 0xFF)); buffer.put((byte)((pixel >> 8) & 0xFF)); buffer.put((byte)(pixel & 0xFF)); buffer.put((byte)((pixel >> 24) & 0xFF)); } } buffer.flip(); if (textureID == Integer.MIN_VALUE) textureID = glGenTextures(); glBindTexture(GL_TEXTURE_2D, textureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); return textureID; } public int getWidth(String string, int height) { return (int)Math.ceil(getWidth(string) * (float)height / fontHeight); } public int getWidth(String string) { int width = 0; CharData charData; char currentChar; for (int i = 0; i < string.length(); i++) { currentChar = string.charAt(i); if (currentChar < 256) { charData = charArray[currentChar]; } else { charData = customChars.get(currentChar); } if (charData != null) width += charData.width; } return width; } /** * Trims a string to a specified width, and will reverse it if par3 is set. */ public String trimStringToWidth(String string, int newLength, boolean reverse) { StringBuilder stringbuilder = new StringBuilder(); int width = 0; int k = reverse ? string.length() - 1 : 0; int l = reverse ? -1 : 1; boolean flag1 = false; boolean flag2 = false; for (int i1 = k; i1 >= 0 && i1 < string.length() && width < newLength; i1 += l) { char thisChar = string.charAt(i1); int thisWidth = getCharWidth(thisChar); if (flag1) { flag1 = false; if (thisChar != 108 && thisChar != 76) { if (thisChar == 114 || thisChar == 82) { flag2 = false; } } else { flag2 = true; } } else if (thisWidth < 0) { flag1 = true; } else { width += thisWidth; if (flag2) { ++width; } } if (width > newLength) { break; } if (reverse) { stringbuilder.insert(0, thisChar); } else { stringbuilder.append(thisChar); } } return stringbuilder.toString(); } private int getCharWidth(char character) { CharData charData; if (character < 256) { charData = charArray[character]; } else { charData = customChars.get(character); } return charData == null ? 0 : charData.width; } public int getHeight(String string) { return fontHeight; } public int getLineHeight() { return fontHeight; } public void drawString(float x, float y, String string) { drawString(x, y, string, 0xFFFFFFFF); } public void drawString(float x, float y, String string, int colour) { drawString(x, y, string, colour, 0, string.length() - 1); } public void drawString(float x, float y, String string, int colour, int startIndex, int endIndex) { float red = (float)(colour >> 16 & 255) / 255.0F; float blue = (float)(colour >> 8 & 255) / 255.0F; float green = (float)(colour & 255) / 255.0F; glColor3f(red, blue, green); glBindTexture(GL_TEXTURE_2D, this.textureID); CharData charData; char charCurrent; glBegin(GL_QUADS); int width = 0; for (int i = 0; i < string.length(); i++) { charCurrent = string.charAt(i); if (charCurrent < 256) { charData = charArray[charCurrent]; } else { charData = customChars.get(charCurrent); } if (charData != null) { if ((i >= startIndex) || (i <= endIndex)) { drawQuad((x + width), y, charData.storedX, charData.storedY, charData.width, charData.height); } width += charData.width; } } glEnd(); } private void drawQuad(float drawX, float drawY, float srcX, float srcY, float w, float h) { float tSrcX = srcX / textureWidth; float tSrcY = srcY / textureHeight; float drawX2 = drawX + w; float drawY2 = drawY + h; float u = (w / textureWidth); float v = (h / textureHeight); glTexCoord2f(tSrcX, tSrcY); glVertex3f(drawX, drawY, zLevel); glTexCoord2f(tSrcX, tSrcY + v); glVertex3f(drawX, drawY2, zLevel); glTexCoord2f(tSrcX + u, tSrcY + v); glVertex3f(drawX2, drawY2, zLevel); glTexCoord2f(tSrcX + u, tSrcY); glVertex3f(drawX2, drawY, zLevel); } public void drawScaledString(float x, float y, String string, int colour, int height) { float scale = (float)height / getHeight(); glPushMatrix(); glTranslatef(x, y, 0); glScalef(scale, scale, 1); drawString(0, 0, string, colour); glPopMatrix(); } public int getHeight() { return fontHeight; } /** * Inserts newline and formatting into a string to wrap it within the specified width. */ private String wrapFormattedStringToWidth(String string, int maxWidth) { int j = this.sizeStringToWidth(string, maxWidth); if (string.length() <= j) { return string; } else { String s1 = string.substring(0, j); char c0 = string.charAt(j); boolean flag = c0 == 32 || c0 == 10; String s2 = string.substring(j + (flag ? 1 : 0)); return s1 + "\n" + this.wrapFormattedStringToWidth(s2, maxWidth); } } /** * Determines how many characters from the string will fit into the specified width. */ private int sizeStringToWidth(String string, int width) { int stringLength = string.length(); int k = 0; int l = 0; int i1 = -1; for (boolean flag = false; l < stringLength; ++l) { char c0 = string.charAt(l); switch (c0) { case 10: --l; break; case 167: if (l < stringLength - 1) { ++l; char c1 = string.charAt(l); if (c1 != 108 && c1 != 76) { if (c1 == 114 || c1 == 82) { flag = false; } } else { flag = true; } } break; case 32: i1 = l; default: k += this.getCharWidth(c0); if (flag) { ++k; } } if (c0 == 10) { ++l; i1 = l; break; } if (k > width) { break; } } return l != stringLength && i1 != -1 && i1 < l ? i1 : l; } private static class CharData { public int width; public int height; public int storedX; public int storedY; } }