package advancedsystemsmanager.client.gui.fonts;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.IResource;
import net.minecraft.util.ResourceLocation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
/**
* A font metric digest. Contains information on the font, such as the
* orientation and size of each glyph supported, the texture coordinate for each
* glyph and the resource mappings to the font image file.
*
* @author AfterLifeLochie
*/
public class GLFontMetrics
{
/**
* The individual dimensions and u-v locations of each character in the set
*/
public final HashMap<Integer, GLGlyphMetric> glyphs = new HashMap<Integer, GLGlyphMetric>();
/**
* The universal width of the font image.
*/
public final float fontImageWidth;
/**
* The universal height of the font image.
*/
public final float fontImageHeight;
private GLFontMetrics(int fontImageWidth, int fontImageHeight)
{
this.fontImageWidth = fontImageWidth;
this.fontImageHeight = fontImageHeight;
}
/**
* Derive a font metric from a font file, a font render context and the
* layout properties specified.
*
* @param font The Font to read from
* @param ctx The rendering context
* @param fontImageWidth The font image width
* @param fontImageHeight The font image height
* @param charsPerRow The number of characters per row on the image
* @param minChar The starting character
* @param maxChar The ending character
* @return A GLFontMetrics object which appropriates the location of all
* fonts on the buffer, based on the parameters provided.
*/
public static GLFontMetrics fromFontMetrics(Font font, FontRenderContext ctx, int fontImageWidth,
int fontImageHeight, int charsPerRow, char minChar, char maxChar)
{
if (font == null)
throw new IllegalArgumentException("font may not be null");
if (ctx == null)
throw new IllegalArgumentException("ctx may not be null");
int off = 0;
GLFontMetrics metric = new GLFontMetrics(fontImageWidth, fontImageHeight);
for (char k = minChar; k <= maxChar; k++, off++)
{
TextLayout layout = new TextLayout(String.valueOf(k), font, ctx);
Rectangle2D rect = layout.getBounds();
int x = (off % charsPerRow) * (fontImageWidth / charsPerRow);
int y = (off / charsPerRow) * (fontImageWidth / charsPerRow);
float cy = (float)rect.getHeight();
Rectangle rect0 = layout.getPixelBounds(null, 100, 100);
float cx = -(rect0.x - 100);
int u = (int)Math.ceil(rect.getWidth() + cx);
int v = (int)Math.ceil(layout.getAscent() + layout.getDescent());
metric.glyphs.put((int)k,
new GLGlyphMetric(u, v, (int)layout.getAscent(), (int)(x - cx), (int)(y - cy)));
}
return metric;
}
/**
* Derive a font metric from an XML document path and the layout properties
* specified.
*
* @param fontMetricName The path to the XML metrics document
* @param fontImageWidth The font image width
* @param fontImageHeight The font image height
* @return A GLFontMetrics object which appropriates the location of all
* fonts on the buffer, based on the parameters provided.
*/
public static GLFontMetrics fromResource(ResourceLocation fontMetricName, int fontImageWidth,
int fontImageHeight)
{
if (fontMetricName == null)
throw new IllegalArgumentException("fontMetricName may not be null");
try
{
IResource metricResource = Minecraft.getMinecraft().getResourceManager().getResource(fontMetricName);
InputStream stream = metricResource.getInputStream();
if (stream == null)
throw new IOException("Could not open font metric file.");
GLFontMetrics metric = new GLFontMetrics(fontImageWidth, fontImageHeight);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(stream);
Element metrics = doc.getDocumentElement();
NodeList list_character = metrics.getElementsByTagName("character");
for (int i = 0; i < list_character.getLength(); i++)
{
Element character = (Element)list_character.item(i);
int charcode = Integer.parseInt(character.getAttributes().getNamedItem("key").getNodeValue());
if (0 > charcode || charcode > 255)
continue;
int w = -1, h = -1, u = -1, v = -1;
NodeList character_properties = character.getChildNodes();
for (int k = 0; k < character_properties.getLength(); k++)
{
Node property = character_properties.item(k);
if (!(property instanceof Element))
continue;
Element elem = (Element)property;
String name = elem.getNodeName().toLowerCase();
int val = Integer.parseInt(elem.getFirstChild().getNodeValue());
if (name.equals("width"))
w = val;
else if (name.equals("height"))
h = val;
else if (name.equals("x"))
u = val;
else if (name.equals("y"))
v = val;
}
metric.glyphs.put(charcode, new GLGlyphMetric(w, h, h, u, v));
}
return metric;
} catch (IOException e)
{
} catch (ParserConfigurationException e)
{
} catch (SAXException e)
{
}
return null;
}
public GLGlyphMetric getGlyphMetric(char c)
{
return glyphs.containsKey((int)c) ? glyphs.get((int)c) : null;
}
@Override
public String toString()
{
return "GLFontMetrics { hash: " + System.identityHashCode(this) + ", w: " + fontImageWidth + ", h: "
+ fontImageHeight + " }";
}
}