package advancedsystemsmanager.client.gui.fonts; import net.minecraft.client.Minecraft; import net.minecraft.client.resources.IResource; import net.minecraft.util.ResourceLocation; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import javax.imageio.ImageIO; import java.awt.*; import java.awt.color.ColorSpace; import java.awt.font.TextLayout; import java.awt.geom.Rectangle2D; import java.awt.image.*; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.IntBuffer; import java.util.Hashtable; /** * Represents a Font object for OpenGL. * <p/> * Shamelessly adapted from Fontbox by AfterLifeLochie: https://github.com/AfterLifeLochie/fontbox */ public class GLFont { private static final char MIN_CH = '\u0000'; private static final char MAX_CH = '\u00ff'; private static final int RASTER_DIM = 512; private String name; private float scale; private int textureId; private GLFontMetrics metric; private GLFont(String name, int textureId, float scale, GLFontMetrics metric) { this.name = name; this.textureId = textureId; this.scale = scale; this.metric = metric; } /** * Create a GLFont from a TTF file * * @param px The font pixel size * @param ttf The TTF file * @return The GLFont result */ public static GLFont fromTTF(float px, ResourceLocation ttf) { if (ttf == null) throw new IllegalArgumentException("ttf may not be null"); try { IResource metricResource = Minecraft.getMinecraft().getResourceManager().getResource(ttf); InputStream stream = metricResource.getInputStream(); if (stream == null) throw new IOException("Could not open TTF file."); Font sysfont = Font.createFont(Font.TRUETYPE_FONT, stream); return fromFont(sysfont.deriveFont(px)); } catch (FontFormatException e) { } catch (IOException e) { } return null; } /** * Create a GLFont from a Java Font object * * @param font The font object * @return The GLFont result */ public static GLFont fromFont(Font font) { if (font == null) throw new IllegalArgumentException("font may not be null"); BufferedImage buffer = new BufferedImage(RASTER_DIM, RASTER_DIM, BufferedImage.TYPE_INT_ARGB); Graphics2D graphics = (Graphics2D)buffer.getGraphics(); graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); int off = 0; int charsPerRow = 12; for (char k = MIN_CH; k <= MAX_CH; k++, off++) { TextLayout layout = new TextLayout(String.valueOf(k), font, graphics.getFontRenderContext()); Rectangle2D rect = layout.getBounds(); int x = (off % charsPerRow) * (RASTER_DIM / charsPerRow); int y = (off / charsPerRow) * (RASTER_DIM / charsPerRow); float cy = (float)rect.getHeight(); graphics.setColor(Color.WHITE); layout.draw(graphics, x, y - cy); } GLFontMetrics metric = GLFontMetrics.fromFontMetrics(font, graphics.getFontRenderContext(), RASTER_DIM, RASTER_DIM, charsPerRow, MIN_CH, MAX_CH); GLFont f0 = fromBuffer(font.getFontName(), buffer, RASTER_DIM, RASTER_DIM, metric); return f0; } /** * Create a GLFont from an image buffer of a specified size with a specified * metric map. * * @param name The name of the font * @param image The buffered image * @param width The width of the image, absolute pixels * @param height The height of the image, absolute pixels * @param metric The font metric map * @return The GLFont result */ public static GLFont fromBuffer(String name, BufferedImage image, int width, int height, GLFontMetrics metric) { if (name == null) throw new IllegalArgumentException("name may not be null"); if (image == null) throw new IllegalArgumentException("image may not be null"); if (metric == null) throw new IllegalArgumentException("metric may not be null"); ColorModel glAlphaColorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[]{ 8, 8, 8, 8}, true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); WritableRaster raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 4, null); BufferedImage texImage = new BufferedImage(glAlphaColorModel, raster, true, new Hashtable<Object, Object>()); Graphics g = texImage.getGraphics(); g.setColor(new Color(0f, 0f, 0f, 0f)); g.fillRect(0, 0, width, height); g.drawImage(image, 0, 0, null); byte[] data = ((DataBufferByte)texImage.getRaster().getDataBuffer()).getData(); ByteBuffer buffer = ByteBuffer.allocateDirect(data.length); buffer.order(ByteOrder.nativeOrder()); buffer.put(data, 0, data.length); buffer.flip(); IntBuffer tmp = BufferUtils.createIntBuffer(1); GL11.glGenTextures(tmp); tmp.rewind(); GL11.glBindTexture(GL11.GL_TEXTURE_2D, tmp.get(0)); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); tmp.rewind(); int texIdx = tmp.get(0); GLFont font = new GLFont(name, texIdx, 0.44f, metric); // Fontbox.allocateFont(font); return font; } /** * Create a GLFont from a spritefont and XML descriptor * * @param name The name of the font, case sensitive * @param image The image file * @param xml The XML descriptor file * @return The GLFont result */ public static GLFont fromSpritefont(String name, ResourceLocation image, ResourceLocation xml) { if (name == null) throw new IllegalArgumentException("name may not be null"); if (image == null) throw new IllegalArgumentException("image may not be null"); if (xml == null) throw new IllegalArgumentException("xml may not be null"); try { IResource imageResource = Minecraft.getMinecraft().getResourceManager().getResource(image); InputStream stream = imageResource.getInputStream(); if (stream == null) throw new IOException("Could not open image file."); BufferedImage buffer = ImageIO.read(stream); GLFontMetrics metric = GLFontMetrics.fromResource(xml, buffer.getWidth(), buffer.getHeight()); GLFont f0 = fromBuffer(name, buffer, buffer.getWidth(), buffer.getHeight(), metric); return f0; } catch (IOException ioex) { } return null; } /** * Get the name of the font. * * @return The name of the font */ public String getName() { return name; } /** * Get the OpenGL texture ID for this font. * * @return The 2D texture ID for the font */ public int getTextureId() { return textureId; } /** * Get the OpenGL font scale for this font. * * @return The 2D font scaling ratio */ public float getScale() { return scale; } public float getTextureSize() { return RASTER_DIM; } /** * Get the font metric map associated with this font. * * @return The metric map */ public GLFontMetrics getMetric() { return metric; } /** * Delete the font. This releases all the resources associated with the font * immediately. */ public void delete() { // Fontbox.deleteFont(this); GL11.glDeleteTextures(textureId); textureId = -1; name = null; metric = null; } @Override public String toString() { return "GLFont { hash: " + System.identityHashCode(this) + ", texture: " + textureId + ", metric: " + System.identityHashCode(metric) + " }"; } }