package buildcraft.core.tablet.utils; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import gnu.trove.map.TIntObjectMap; import gnu.trove.map.hash.TIntObjectHashMap; import buildcraft.api.tablet.TabletBitmap; public final class TabletFont { public final class Glyph { public byte[] glyphData; private final int loadOffset; private int width, height, xOffset, yOffset, deviceWidth; public Glyph(int offset) { this.loadOffset = offset; } public void load(byte[] data, int offsetBase) throws Exception { ByteArrayInputStream stream = new ByteArrayInputStream(data); stream.skip(loadOffset - offsetBase); width = readUnsignedShort(stream); height = readUnsignedShort(stream); xOffset = readShort(stream); yOffset = readShort(stream); deviceWidth = readShort(stream); glyphData = new byte[(width * height + 7) / 8]; stream.read(glyphData); } public int getWidth() { return width; } public int getHeight() { return height; } public int getDeviceWidth() { return deviceWidth; } public int getXOffset() { return xOffset; } public int getYOffset() { return yOffset; } public int draw(TabletBitmap bitmap, int x, int y, int intensity) { // TODO: Why do we have to do this? int yTop = y - (yOffset * 2) - height; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { int bPos = (i + (j * width)) >> 3; int bMask = 128 >> ((i + (j * width)) & 7); if ((glyphData[bPos] & bMask) != 0) { bitmap.set(x + xOffset + i, yTop + j, intensity); } } } return deviceWidth; } } private boolean isBold; private boolean isItalic; private int pointSize, maxW, maxH, ascent, descent; private TIntObjectMap<Glyph> glyphs = new TIntObjectHashMap<Glyph>(); public TabletFont(File file) throws Exception { this(new FileInputStream(file)); } public TabletFont(InputStream stream) throws Exception { int loaded = 0; while (stream.available() > 0) { String section = readString(stream, 4); int sectionLength = readInt(stream); loaded += 8; if ("FAMI".equals(section)) { readString(stream, sectionLength); } else if ("WEIG".equals(section)) { this.isBold = "bold".equals(readString(stream, sectionLength)); } else if ("SLAN".equals(section)) { this.isItalic = "italic".equals(readString(stream, sectionLength)); } else if ("PTSZ".equals(section)) { this.pointSize = readUnsignedShort(stream); } else if ("MAXW".equals(section)) { this.maxW = readUnsignedShort(stream); } else if ("MAXH".equals(section)) { this.maxH = readUnsignedShort(stream); } else if ("ASCE".equals(section)) { this.ascent = readUnsignedShort(stream); } else if ("DESC".equals(section)) { this.descent = readUnsignedShort(stream); } else if ("CHIX".equals(section)) { for (int i = 0; i < sectionLength; i += 9) { int codePoint = readInt(stream); stream.skip(1); int offset = readInt(stream); glyphs.put(codePoint, new Glyph(offset)); } } else if ("DATA".equals(section)) { byte[] data = new byte[stream.available()]; stream.read(data); for (Glyph g : glyphs.valueCollection()) { g.load(data, loaded); } } else { stream.skip(sectionLength); } loaded += sectionLength; } stream.close(); } public boolean isBold() { return isBold; } public boolean isItalic() { return isItalic; } public int getPointSize() { return pointSize; } public int getWidth() { return maxW; } public int getHeight() { return maxH; } public int getAscent() { return ascent; } public int getDescent() { return descent; } public Glyph getGlyph(int codePoint) { return glyphs.get(codePoint); } public int getStringWidth(String s) { int width = 0; for (int i = 0; i < s.length(); i++) { width += getGlyph(s.codePointAt(i)).getDeviceWidth(); } return width; } public int draw(TabletBitmap target, String s, int x, int y, int intensity) { int width = 0; for (int i = 0; i < s.length(); i++) { width += getGlyph(s.codePointAt(i)).draw(target, x + width, y + ascent, intensity); } return width; } private static int readUnsignedShort(InputStream stream) { try { int hi = stream.read(); return hi << 8 | stream.read(); } catch (IOException e) { e.printStackTrace(); return 0; } } private static int readShort(InputStream stream) { int t = readUnsignedShort(stream); if (t >= 0x8000) { return 0 - (t ^ 0xFFFF); } else { return t; } } private static int readInt(InputStream stream) { try { int i = stream.read(); i = (i << 8) | stream.read(); i = (i << 8) | stream.read(); i = (i << 8) | stream.read(); return i; } catch (IOException e) { e.printStackTrace(); return 0; } } private static String readString(InputStream stream, int length) { byte[] data = new byte[length]; try { stream.read(data); return new String(data, "ASCII"); } catch (IOException e) { e.printStackTrace(); return ""; } } public static void main(String[] args) { TabletBitmap bitmap = new TabletBitmap(244, 306); try { TabletFont font = new TabletFont(TabletFont.class.getClassLoader().getResourceAsStream("assets/buildcraftcore/tablet/test.pf2")); font.draw(bitmap, "Hello World!", 1, 1, 4); } catch (Exception e) { e.printStackTrace(); } } }