/***********************************************************************
* mt4j Copyright (c) 2008 - 2009 Christopher Ruff, Fraunhofer-Gesellschaft All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
***********************************************************************/
package org.mt4j.components.visibleComponents.font.fontFactories;
import java.awt.Font;
import java.awt.FontMetrics;
import java.util.ArrayList;
import java.util.List;
import org.mt4j.components.visibleComponents.font.BitmapFont;
import org.mt4j.components.visibleComponents.font.BitmapFontCharacter;
import org.mt4j.components.visibleComponents.font.IFont;
import org.mt4j.util.MT4jSettings;
import org.mt4j.util.MTColor;
import processing.core.PApplet;
import processing.core.PConstants;
import processing.core.PFont;
import processing.core.PImage;
/**
* A factory for creating BitmapFont objects.
* @author Christopher Ruff
*/
public class BitmapFontFactory implements IFontFactory {
// static{
// FontManager.getInstance().registerFontFactory("", new BitmapFontFactory());
// }
/* (non-Javadoc)
* @see org.mt4j.components.visibleComponents.font.fontFactories.IFontFactory#createFont(processing.core.PApplet, java.lang.String, int, org.mt4j.util.MTColor, org.mt4j.util.MTColor)
*/
//@Override
public IFont createFont(
PApplet pa,
String fontFileName,
int fontSize,
MTColor fillColor,
MTColor strokeColor
) {
PFont p5Font;
//FIXME when loading the vlw font the font size is already determined with the file
//and our parameter isnt honored
if (fontFileName.endsWith(".vlw")){
int lastDirSeparator = fontFileName.lastIndexOf(java.io.File.separator);
if (lastDirSeparator != -1){
// p5Font = pa.createFont(fontFileName.substring(lastDirSeparator+1, fontFileName.length()), fontSize, false); //FIXME TEST
p5Font = pa.loadFont(fontFileName.substring(lastDirSeparator+1, fontFileName.length()));
}else{
p5Font = pa.loadFont(fontFileName);
}
}
else if (fontFileName.endsWith(".ttf") || fontFileName.endsWith(".otf")){
int lastDirSeparator = fontFileName.lastIndexOf(java.io.File.separator);
if (lastDirSeparator != -1){
p5Font = pa.createFont(fontFileName.substring(lastDirSeparator+1, fontFileName.length()), fontSize, true);
}else{
p5Font = pa.loadFont(fontFileName);
}
}
else{
int lastDirSeparator = fontFileName.lastIndexOf(java.io.File.separator);
if (lastDirSeparator != -1){
p5Font = pa.createFont(fontFileName.substring(lastDirSeparator+1, fontFileName.length()), fontSize, true); //Creats the font?
}else{
p5Font = pa.loadFont(fontFileName);
}
}
// char[] chars = new char[]{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','�','�','�','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','�','�','�','<','>','|',',',';','.',':','-','_','#','\'','+','*','!','?','\\','$','%','&','/','(',')','=','�','~','�','�','{','[',']','}','^','@','�',' '};
char[] chars = new char[]{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','�','�','�','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','�','�','�','<','>','|',',',';','.',':','-','_','#','\'','+','*','!','?','\\','$','%','&','/','(',')','=','�','~','{','[',']','}','^','@','�',' '};
List<BitmapFontCharacter> bitMapCharacters = new ArrayList<BitmapFontCharacter>();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
int charIndex = p5Font.index(c);
if (charIndex != -1){
PImage charImage = p5Font.images[charIndex];
int charWidth = p5Font.width[charIndex];
int charHeight = p5Font.height[charIndex];
int topExtend = p5Font.topExtent[charIndex];
int leftExtend = p5Font.leftExtent[charIndex];
int widthDisplacement = p5Font.setWidth[charIndex];
// float high = (float) p5Font.height[charIndex] / p5Font.fheight;
// float bwidth = (float) p5Font.width[charIndex] / p5Font.fwidth;
// float lextent = (float) p5Font.leftExtent[charIndex] / p5Font.fwidth;
// float textent = (float) p5Font.topExtent[charIndex] / p5Font.fheight;
// int topOffset = p5Font.descent + (-charHeight - (topExtend-charHeight)); //ORIGINAL
int topOffset = (-charHeight - (topExtend-charHeight));
// /*
if (MT4jSettings.getInstance().isOpenGlMode()){
for (int j = 0; j < charImage.pixels.length; j++) {
int d = charImage.pixels[j];
/*
int a = d >> 24 & 0xFF;
int r = d >> 16 & 0xFF;
int g = d >> 8 & 0xFF;
int b = d & 0xFF;
System.out.println("R: " + r + " G:" + g + " B:" + " A:" + a);
*/
charImage.pixels[j] = (d << 24) | 0x00FFFFFF; //ORIGINAL! //make it white
// charImage.pixels[j] = (d << 24) | pa.color(fillRed, fillGreen, fillBlue, 0);
charImage.format = PConstants.ARGB;
}
// /*
//Copy the actual font data on the image from the upper left corner 1 pixel
//into the middle of the image to avoid anti aliasing artefacts at the corners
PImage copy = new PImage(charImage.width, charImage.height, PImage.ARGB);
//Clear transparent
for (int j = 0; j < copy.pixels.length; j++) {
copy.pixels[j] = (copy.pixels[j] << 24) | 0x00FFFFFF; //Original! //make it white
// copy.pixels[j] = (copy.pixels[j] << 24) | pa.color(fillRed, fillGreen, fillBlue, 0);
}
int shiftAmount = 1;
copy.copy(charImage, 0, 0, charWidth, charHeight, shiftAmount, shiftAmount, charWidth, charHeight);
charImage = copy;
//Move the character to compensate for the shifting of the image
topOffset -= shiftAmount;
leftExtend -= shiftAmount;
// */
}
// */
//Create bitmap font character
String StringChar = new Character(c).toString();
BitmapFontCharacter character = new BitmapFontCharacter(charImage, pa, StringChar, leftExtend, topOffset, widthDisplacement);
character.setName(StringChar);
character.setFillColor(new MTColor(fillColor.getR(), fillColor.getG(), fillColor.getB(), fillColor.getAlpha()));
if (MT4jSettings.getInstance().isOpenGlMode()){
character.generateAndUseDisplayLists();
}
bitMapCharacters.add(character);
// System.out.println("Char: " + c + " charWidth: " + charWidth + " leftExtend: " + leftExtend + " widthDisplacement: " + widthDisplacement + " imageHeight: " + charImage.height + " charHeight: " + charHeight + " topExtent: " + topExtend);
}else{
System.err.println("Char : " + c + " not found!");
}
}
//font is null sometimes (vlw)
/*
Font f = p5Font.getFont();
FontMetrics fm = pa.getFontMetrics(f);
Map<TextAttribute, ?> atts = f.getAttributes();
Set<TextAttribute> attKeys = atts.keySet();
for (Iterator iterator = attKeys.iterator(); iterator.hasNext();) {
TextAttribute textAttribute = (TextAttribute) iterator.next();
Object value = atts.get(textAttribute);
System.out.println("Key: " + textAttribute + " Value: " + value);
}
// FontMetrics fm = Toolkit.getDefaultToolkit().getFontMetrics(f);
*/
int defaultHorizontalAdvX = bitMapCharacters.get(0).getHorizontalDist(); //FIXME HACK!
String fontFamily = p5Font.psname;
// String fontFamily = f.getFamily();
int fontMaxAscent = p5Font.ascent;
int fontMaxDescent = p5Font.descent;
//TODO INFO: because in vector font this is a negative value, too
Font f = p5Font.getFont();
if (f != null){
FontMetrics fm = pa.getFontMetrics(f);
fontMaxDescent = fm.getDescent();
}
fontMaxDescent *= -1; //We use negative descent values
//System.out.println("Bitmapfont max descent: " + fontMaxDescent);
// int fontMaxAscent = Math.round(p5Font.ascent()*fontSize);
// int fontMaxDescent = Math.round(p5Font.descent()*fontSize);
// int fontMaxAscent = fm.getMaxAscent();
// int fontMaxDescent = fm.getMaxDescent();
int unitsPerEm = 1000; //FIXME HACK!
int originalFontSize = fontSize; //important for font cache
PImage dummy = new PImage(1,1);
// /*
//Manually add a newLine character to the font
BitmapFontCharacter newLine = new BitmapFontCharacter(dummy, pa, "\n", 0, 0, 0);
// newLine.setSizeLocal(defaultHorizontalAdvX, defaultHorizontalAdvX);
newLine.setPickable(false);
newLine.setVisible(false);
newLine.setNoFill(true);
newLine.setNoStroke(true);
newLine.setName("newline");
bitMapCharacters.add(newLine);
//Manually add a SPACE character to the font
// int spaceAdvancex = defaultHorizontalAdvX;
// int spaceAdvancex = fm.charWidth(' ');
int spaceIndex = p5Font.index('-');
int spaceAdvancex = p5Font.width[spaceIndex];
// int spaceAdvancex = Math.round(pa.textWidth(' '));
// int spaceAdvancex = Math.round(p5Font.width(' ') * p5Font.size);
BitmapFontCharacter space = new BitmapFontCharacter(dummy, pa, " ", 0, 0, spaceAdvancex);
space.setPickable(false);
space.setVisible(false);
space.setNoFill(true);
space.setNoStroke(true);
space.setName("space");
bitMapCharacters.add(space);
//Manually add a TAB character to the font
int defaultTabWidth = spaceAdvancex*4;
BitmapFontCharacter tab = new BitmapFontCharacter(dummy, pa, "\t", 0, 0, defaultTabWidth);
try {
int tabWidth = 4 * space.getHorizontalDist();
tab.setHorizontalDist(tabWidth);
} catch (Exception e) {
tab.setHorizontalDist(defaultTabWidth);
}
tab.setPickable(false);
tab.setName("tab");
tab.setVisible(false);
tab.setNoFill(true);
tab.setNoStroke(true);
bitMapCharacters.add(tab);
// */
//TODO bitmap font size seems different to same size vector font, we must have check descent -> textarea -> res*em*etc
//TODO eureka numbers baseline wrong?
//Create the bitmap font
BitmapFontCharacter[] characters = bitMapCharacters.toArray(new BitmapFontCharacter[bitMapCharacters.size()]);
BitmapFont bitmapFont = new BitmapFont(characters, defaultHorizontalAdvX, fontFamily, fontMaxAscent, fontMaxDescent, unitsPerEm, originalFontSize,
fillColor,
strokeColor
);
bitmapFont.setFontFileName(fontFileName);
return bitmapFont;
}
}