PageRenderTime 77ms CodeModel.GetById 14ms app.highlight 55ms RepoModel.GetById 1ms app.codeStats 1ms

/src/processing/core/BitmapFontFactoryProxy.java

http://mt4j.googlecode.com/
Java | 495 lines | 219 code | 50 blank | 226 comment | 30 complexity | c4edc1f2dbb9c0b4e48c393e5ac0176f MD5 | raw file
  1/***********************************************************************
  2 * mt4j Copyright (c) 2008 - 2010 Christopher Ruff, Fraunhofer-Gesellschaft All rights reserved.
  3 *  
  4 *   This program is free software: you can redistribute it and/or modify
  5 *   it under the terms of the GNU General Public License as published by
  6 *   the Free Software Foundation, either version 3 of the License, or
  7 *   (at your option) any later version.
  8 *
  9 *   This program is distributed in the hope that it will be useful,
 10 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 *   GNU General Public License for more details.
 13 *
 14 *   You should have received a copy of the GNU General Public License
 15 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 16 *
 17 ***********************************************************************/
 18package processing.core;
 19
 20import java.io.FileNotFoundException;
 21import java.util.ArrayList;
 22import java.util.List;
 23
 24import org.mt4j.MTApplication;
 25import org.mt4j.components.visibleComponents.font.BitmapFont;
 26import org.mt4j.components.visibleComponents.font.BitmapFontCharacter;
 27import org.mt4j.components.visibleComponents.font.IFont;
 28import org.mt4j.components.visibleComponents.font.fontFactories.IFontFactory;
 29import org.mt4j.util.MT4jSettings;
 30import org.mt4j.util.MTColor;
 31import org.mt4j.util.logging.ILogger;
 32import org.mt4j.util.logging.MTLoggerFactory;
 33
 34import processing.core.PFont.Glyph;
 35
 36/**
 37 * A factory for creating BitmapFont objects.
 38 * @author Christopher Ruff
 39 */
 40public class BitmapFontFactoryProxy implements IFontFactory {
 41	/** The Constant logger. */
 42	private static final ILogger logger;
 43//	= MTLoggerFactory.getLogger(BitmapFontFactoryProxy.class.getName());
 44	static{
 45		logger = MTLoggerFactory.getLogger(BitmapFontFactoryProxy.class.getName());
 46//		logger.setLevel(ILogger.ERROR);
 47//		logger.setLevel(ILogger.WARN);
 48		logger.setLevel(ILogger.DEBUG);
 49	}
 50	
 51	public static String defaultCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÁ?É?Í?Ó?abcdefghijklmnopqrstuvwxyzá?é?í?ó?<>|,;.:-_#'+*!\"§$%&/()=?´{[]}\\@";
 52	
 53//	static{
 54//		FontManager.getInstance().registerFontFactory("", new BitmapFontFactory());
 55	//	}
 56	
 57	public IFont getCopy(IFont font) {
 58		if (font instanceof BitmapFont) {
 59			BitmapFont bf = (BitmapFont) font;
 60			BitmapFont copy = new BitmapFont((BitmapFontCharacter[]) bf.getCharacters(), bf.getDefaultHorizontalAdvX(), bf.getFontFamily(), bf.getFontMaxAscent(), bf.getFontMaxDescent(), bf.getUnitsPerEM(), bf.getOriginalFontSize(), bf.getFillColor(),  /*bf.getStrokeColor(),*/ bf.isAntiAliased());
 61			return copy;
 62		}
 63		return null;
 64	}
 65	
 66	public IFont createFont(PApplet pa, String fontName, int fontSize, MTColor color) {
 67		return this.createFont(pa, fontName, fontSize, color, color, true);
 68	}
 69
 70	public IFont createFont(PApplet pa, String fontName, int fontSize, MTColor color, boolean antiAliased) {
 71		return this.createFont(pa, fontName, fontSize, color, color, antiAliased);
 72	}
 73
 74	/* (non-Javadoc)
 75	 * @see org.mt4j.components.visibleComponents.font.fontFactories.IFontFactory#createFont(processing.core.PApplet, java.lang.String, int, org.mt4j.util.MTColor, org.mt4j.util.MTColor)
 76	 */
 77	public IFont createFont(
 78			PApplet pa, 
 79			String fontFileName, 
 80			int fontSize,
 81			MTColor fillColor, 
 82			MTColor strokeColor
 83	) {
 84		return this.createFont(pa, fontFileName, fontSize, fillColor, strokeColor, true);
 85	}
 86	
 87	/* (non-Javadoc)
 88	 * @see org.mt4j.components.visibleComponents.font.fontFactories.IFontFactory#createFont(processing.core.PApplet, java.lang.String, int, org.mt4j.util.MTColor, org.mt4j.util.MTColor)
 89	 */
 90	public IFont createFont(
 91			PApplet pa, 
 92			String fontFileName, 
 93			int fontSize,
 94			MTColor fillColor, 
 95			MTColor strokeColor,
 96			boolean antiAliased
 97	) {
 98		PFont p5Font = null;
 99		try {
100			p5Font = this.getProcessingFont(pa, fontFileName, fontSize, antiAliased);
101		} catch (FileNotFoundException e1) {
102			e1.printStackTrace();
103		}
104		List<BitmapFontCharacter> bitMapCharacters = this.createCharacters(pa, p5Font, defaultCharacters, fillColor /*, strokeColor*/);
105	
106		//font is null sometimes (vlw)
107		/*
108		Font f = p5Font.getFont();
109		FontMetrics fm = pa.getFontMetrics(f); 
110		Map<TextAttribute, ?> atts = f.getAttributes();
111		Set<TextAttribute> attKeys = atts.keySet();
112		for (Iterator iterator = attKeys.iterator(); iterator.hasNext();) {
113			TextAttribute textAttribute = (TextAttribute) iterator.next();
114			Object value = atts.get(textAttribute);
115			logger.debug("Key: " + textAttribute + " Value: " + value);
116		}
117//		FontMetrics fm = Toolkit.getDefaultToolkit().getFontMetrics(f);
118		 */
119		
120		int defaultHorizontalAdvX = (!bitMapCharacters.isEmpty())? bitMapCharacters.get(0).getHorizontalDist() : Math.round(p5Font.descent() * fontSize); //FIXME HACK!
121		String fontFamily = p5Font.getPostScriptName();
122//		String fontFamily = f.getFamily(); 
123		//FIXME ascent() and descent() return to small values! wheres the difference??
124		int fontMaxAscent = Math.round(p5Font.ascent()* (fontSize));
125		fontMaxAscent +=(float)fontSize/5.5f; //FIXME HACK! because the same ttf fonts seem to have bigger ascents
126//		int fontMaxAscent = p5Font.lazyMetrics.getAscent();
127		int fontMaxDescent = Math.round(p5Font.descent() * fontSize);
128		/*
129		//TODO INFO: because in vector font this is a negative value, too
130		Font f = p5Font.getFont();
131		if (f != null){
132			FontMetrics fm = pa.getFontMetrics(f);
133			fontMaxDescent = fm.getDescent();
134		}
135		*/
136		fontMaxDescent *= -1; //We use negative descent values
137		
138		//logger.debug("Bitmapfont max descent: " + fontMaxDescent);
139		
140//		int fontMaxAscent = Math.round(p5Font.ascent()*fontSize);
141//		int fontMaxDescent = Math.round(p5Font.descent()*fontSize);
142//		int fontMaxAscent = fm.getMaxAscent(); 
143//		int fontMaxDescent = fm.getMaxDescent(); 
144		int unitsPerEm = 1000; //FIXME HACK!
145		int originalFontSize = fontSize; //important for font cache
146		
147		PImage dummy = new PImage(1,1);
148//		/*
149		//Manually add a newLine character to the font
150		BitmapFontCharacter newLine = new BitmapFontCharacter(pa, dummy, "\n", 0, 0, 0);
151		newLine.setPickable(false);						    		
152		newLine.setVisible(false);
153		newLine.setNoFill(true);
154		newLine.setNoStroke(true);
155		newLine.setName("newline");
156		bitMapCharacters.add(newLine);
157		
158		//Manually add a SPACE character to the font
159//		int spaceAdvancex = defaultHorizontalAdvX;
160//		int spaceAdvancex = fm.charWidth(' '); 
161		//TODO hack, we use the dash character's width for the space width, because dont know how to get it
162//		int spaceIndex = p5Font.index('-');
163//		int spaceAdvancex = p5Font.width[spaceIndex];
164//		int spaceAdvancex = p5Font.getGlyph('-').width;
165		int spaceAdvancex = Math.round((p5Font.width('i') * (float) fontSize));
166//		int spaceAdvancex = Math.round(pa.textWidth(' '));
167//		int spaceAdvancex = Math.round(p5Font.width(' ') * p5Font.size);
168		BitmapFontCharacter space = new BitmapFontCharacter(pa, dummy, " ", 0, 0, spaceAdvancex);
169		space.setPickable(false);						    		
170		space.setVisible(false);
171		space.setNoFill(true);
172		space.setNoStroke(true);
173		space.setName("space");
174		bitMapCharacters.add(space);
175		
176		//Manually add a TAB character to the font
177		int defaultTabWidth = spaceAdvancex*4;
178		BitmapFontCharacter tab = new BitmapFontCharacter(pa, dummy, "\t", 0, 0, defaultTabWidth);
179		try {
180			int tabWidth = 4 * space.getHorizontalDist();
181			tab.setHorizontalDist(tabWidth);
182		} catch (Exception e) {
183			tab.setHorizontalDist(defaultTabWidth);
184		}
185		tab.setPickable(false);
186		tab.setName("tab"); 
187		tab.setVisible(false);
188		tab.setNoFill(true);
189		tab.setNoStroke(true);
190		bitMapCharacters.add(tab);
191//		*/
192		
193		//TODO bitmap font size seems different to same size vector font, we must have check descent -> textarea -> res*em*etc
194		//TODO eureka font -  numbers baseline wrong?
195		
196		//Create the bitmap font
197		BitmapFontCharacter[] characters = bitMapCharacters.toArray(new BitmapFontCharacter[bitMapCharacters.size()]);
198		BitmapFont bitmapFont = new BitmapFont(characters, defaultHorizontalAdvX, fontFamily, fontMaxAscent, fontMaxDescent, unitsPerEm, originalFontSize, 
199				fillColor,
200//				strokeColor,
201				antiAliased
202		);
203		bitmapFont.setFontFileName(fontFileName);
204		return bitmapFont;
205	}
206	
207	
208//	/**
209//	 * Gets the processing font.
210//	 *
211//	 * @param pa the pa
212//	 * @param fontFileName the font file name
213//	 * @param fontSize the font size
214//	 * @return the processing font
215//	 */
216//	private PFont getProcessingFont(PApplet pa, String fontFileName, int fontSize){
217//		return this.getProcessingFont(pa, fontFileName, fontSize, true);
218//	}
219
220	/**
221	 * Gets the processing font.
222	 *
223	 * @param pa the pa
224	 * @param fontFileName the font file name
225	 * @param fontSize the font size
226	 * @param antiAliased the anti aliased
227	 * @return the processing font
228	 * @throws FileNotFoundException 
229	 */
230	private PFont getProcessingFont(PApplet pa, String fontFileName, int fontSize, boolean antiAliased) throws FileNotFoundException{
231		PFont p5Font;
232		//When loading the vlw font the font size and anti aliasing is already determined with the file
233		//and our parameter isnt honored
234		if (fontFileName.endsWith(".vlw")){
235			p5Font = pa.loadFont(fontFileName);
236			//If not found try to load from the "/data" directory
237			if (p5Font == null){
238				int lastDirFileSeparator = fontFileName.lastIndexOf(java.io.File.separator);
239				int lastDirSeparator = fontFileName.lastIndexOf(MTApplication.separator);
240				if (lastDirFileSeparator != -1){
241					p5Font = pa.loadFont(fontFileName.substring(lastDirFileSeparator+1, fontFileName.length()));
242				}else if (lastDirSeparator != -1){
243					p5Font = pa.loadFont(fontFileName.substring(lastDirSeparator+1, fontFileName.length()));
244				}
245			}
246		}
247		else if (fontFileName.endsWith(".ttf") || fontFileName.endsWith(".otf")){
248			p5Font = pa.createFont(fontFileName, fontSize, antiAliased); 
249			//If not found try to load from the "/data" directory
250			if (p5Font == null){
251				int lastDirFileSeparator = fontFileName.lastIndexOf(java.io.File.separator);
252				int lastDirSeparator = fontFileName.lastIndexOf(MTApplication.separator);
253				if (lastDirFileSeparator != -1){
254					p5Font = pa.createFont(fontFileName.substring(lastDirFileSeparator+1, fontFileName.length()), fontSize, antiAliased); 
255				}else if (lastDirSeparator != -1){
256					p5Font = pa.createFont(fontFileName.substring(lastDirSeparator+1, fontFileName.length()), fontSize, antiAliased); 
257				}else{
258					p5Font = pa.loadFont(fontFileName);
259				}
260			}
261		}
262		else{
263			//No file suffix -> Create font from a java/system font
264			int lastDirFileSeparator = fontFileName.lastIndexOf(java.io.File.separator);
265			int lastDirSeparator = fontFileName.lastIndexOf(MTApplication.separator);
266			if (lastDirFileSeparator != -1){
267				p5Font = pa.createFont(fontFileName.substring(lastDirFileSeparator+1, fontFileName.length()), fontSize, antiAliased); //Creats the font
268			}
269			else if (lastDirSeparator != -1){
270				p5Font = pa.createFont(fontFileName.substring(lastDirSeparator+1, fontFileName.length()), fontSize, antiAliased); //Creats the font	
271			}
272			else{
273				p5Font = pa.loadFont(fontFileName);
274			}
275		}
276		
277		if (p5Font == null){
278			throw new FileNotFoundException("Couldn't load the font: " + fontFileName);
279		}
280		return p5Font;
281	}
282	
283	
284	
285	public List<BitmapFontCharacter> getCharacters(PApplet pa, 
286			String chars,
287			MTColor fillColor, 
288//			MTColor strokeColor,
289			String fontFileName, 
290			int fontSize
291	){
292		return this.getCharacters(pa, chars, fillColor, /*strokeColor,*/ fontFileName, fontSize, true);
293	}
294	
295	/**
296	 * Creates the specified characters.
297	 *
298	 * @param pa the pa
299	 * @param chars the chars
300	 * @param fillColor the fill color
301	 * @param strokeColor the stroke color
302	 * @param fontFileName the font file name
303	 * @param fontSize the font size
304	 * @param antiAliased the anti aliased
305	 * @return the characters
306	 */
307	public List<BitmapFontCharacter> getCharacters(PApplet pa, 
308			String chars,
309			MTColor fillColor, 
310//			MTColor strokeColor,
311			String fontFileName, 
312			int fontSize,
313			boolean antiAliased
314	){
315		PFont p5Font = null;
316		try {
317			p5Font = this.getProcessingFont(pa, fontFileName, fontSize, antiAliased);
318		} catch (FileNotFoundException e) {
319			e.printStackTrace();
320		}
321		return createCharacters(pa, p5Font, chars, fillColor /*, strokeColor*/);
322	}
323	
324	
325	private List<BitmapFontCharacter> createCharacters(PApplet pa, PFont p5Font, String chars, MTColor fillColor /*, MTColor strokeColor*/){
326		List<BitmapFontCharacter> bitMapCharacters = new ArrayList<BitmapFontCharacter>();
327		
328		for (int i = 0; i < chars.length(); i++) {
329			char c = chars.charAt(i);
330//			int charIndex = p5Font.index(c);
331			Glyph glyph = p5Font.getGlyph(c);
332			if (glyph != null){
333				PImage charImage = glyph.image;
334				int charWidth = glyph.width;
335				int charHeight = glyph.height;
336				int topExtend = glyph.topExtent;
337				int leftExtend = glyph.leftExtent;
338				int widthDisplacement = glyph.setWidth;
339				
340
341				//int topOffset = p5Font.descent + (-charHeight - (topExtend-charHeight)); //ORIGINAL
342				int topOffset =  (-charHeight - (topExtend-charHeight));
343				
344				//Copy the actual font data on the image from the upper left corner 1 pixel
345				//into the middle of the image to avoid anti aliasing artefacts at the corners
346//				PImage copy = new PImage(charImage.width, charImage.height, PImage.ARGB); //ORG
347
348//				for (int j = 0; j < charImage.pixels.length; j++) { //ORG
349//					int d = charImage.pixels[j];
350//					/*
351//						int a = d >> 24 & 0xFF;
352//						int r = d >> 16 & 0xFF;
353//						int g = d >> 8 & 0xFF;
354//						int b = d & 0xFF;
355//						logger.debug("R: " + r + " G:" + g + " B:" + " A:" + a);
356//					 */
357//					charImage.pixels[j] = (d << 24) | 0x00FFFFFF; //ORIGINAL! //make it white
358////					charImage.pixels[j] = (d << 24) | pa.color(fillColor.getR(), fillColor.getG(), fillColor.getB(), 0);
359////					charImage.pixels[j] = (charImage.pixels[j] << 24) | 0x00FFFFFF;
360//					//charImage.format = PConstants.ARGB;
361//					
362//					//Clear the copy image in the same loop
363//					copy.pixels[j] = (copy.pixels[j] << 24) | 0x00FFFFFF; //Original! //make it white
364////					copy.pixels[j] = (d << 24) | 0x00FFFFFF; //Original! //make it white
365//				}
366				
367				for (int j = 0; j < charImage.pixels.length; j++) { //ORG
368					charImage.pixels[j] = (charImage.pixels[j] << 24) | 0x00FFFFFF; //ORIGINAL! //make it white
369				}
370				
371				//Shift character image data down and right in the image because of aliasing artifacts at the border
372				//we need to compensate for this when displaying the char
373				//FIXME this creates far to big images..but because of artefacts needed..?
374				int topShiftAmount = 4;
375				int leftShiftAmount = 4;
376				
377//				PImage copy = new PImage(ToolsMath.nearestPowerOfTwo(charWidth + shiftAmount), ToolsMath.nearestPowerOfTwo(charHeight + shiftAmount), PImage.ARGB);
378//				
379				PImage copy = new PImage(nextPowerOfTwo(charImage.width + leftShiftAmount + 1), nextPowerOfTwo(charImage.height + topShiftAmount +1), PImage.ARGB);
380//				PImage copy = new PImage(charImage.width + leftShiftAmount + 1, charImage.height + topShiftAmount, PImage.ARGB);
381				
382				copy.copy(charImage, 0, 0, charWidth, charHeight, leftShiftAmount, topShiftAmount, charWidth, charHeight);
383				
384//				copy.copy(charImage, 0, 0, charImage.width, charImage.height, leftShiftAmount, topShiftAmount, charImage.width, charImage.height);
385				
386//				copy.copy(charImage, 0, 0, charWidth, charHeight, shiftAmount, shiftAmount, charWidth, charHeight);
387//				copy.copy(charImage, 0, 0, charImage.width, charImage.height, shiftAmount, shiftAmount, charImage.width, charImage.height);
388//				copy.copy(charImage, 0, 0, charImage.width, charImage.height, shiftAmount, shiftAmount, charImage.width, charImage.height);
389//				copy.copy(charImage, 0, 0, charWidth, charHeight, shiftAmount, shiftAmount, charWidth, charHeight);
390				
391				charImage = copy;
392				
393				//FIXME the topoffset is smaller than with the vector font! check that!
394				//FIXME anti aliasing artefacts may also stem from using a perspective and not ortho camera!!
395				//FIXME space character too wide..
396				
397				//Move the character to compensate for the shifting of the image
398				topOffset -= topShiftAmount; //org shiftamount 
399				leftExtend -= leftShiftAmount;
400				
401				//FIXME TEST
402//				if (c == 'i'){
403//					copy.save(MT4jSettings.DEFAULT_IMAGES_PATH + "i.png");
404//				}
405				
406				//Create bitmap font character
407				String StringChar = Character.toString(c);
408				BitmapFontCharacter character = new BitmapFontCharacter(pa, charImage, StringChar, leftExtend, topOffset, widthDisplacement);
409				character.setName(StringChar);
410				character.setFillColor(new MTColor(fillColor));
411				if (MT4jSettings.getInstance().isOpenGlMode()){
412					character.generateAndUseDisplayLists();
413				}
414				bitMapCharacters.add(character);
415				//logger.debug("Char: " + c + " charWidth: " + charWidth +  " leftExtend: " + leftExtend + " widthDisplacement: " + widthDisplacement + " imageHeight: " + charImage.height + " charHeight: " + charHeight +  " topExtent: " + topExtend);
416			}else{
417				logger.warn("Couldnt create bitmap character : " + c + " -> not found!");
418			}
419		}
420		return bitMapCharacters;
421	}
422	
423	private int nextPowerOfTwo(int val) {
424	      int ret = 1;
425	      while (ret < val) {
426	        ret <<= 1;
427	      }
428	      return ret;
429	    }
430
431//	
432//	  /**
433//	   * Create a .vlw font on the fly from either a font name that's
434//	   * installed on the system, or from a .ttf or .otf that's inside
435//	   * the data folder of this sketch.
436//	   * <P/>
437//	   * Many .otf fonts don't seem to be supported by Java, perhaps because 
438//	   * they're CFF based?
439//	   * <P/>
440//	   * Font names are inconsistent across platforms and Java versions.
441//	   * On Mac OS X, Java 1.3 uses the font menu name of the font,
442//	   * whereas Java 1.4 uses the PostScript name of the font. Java 1.4
443//	   * on OS X will also accept the font menu name as well. On Windows,
444//	   * it appears that only the menu names are used, no matter what
445//	   * Java version is in use. Naming system unknown/untested for 1.5.
446//	   * <P/>
447//	   * Use 'null' for the charset if you want to dynamically create
448//	   * character bitmaps only as they're needed. (Version 1.0.9 and
449//	   * earlier would interpret null as all unicode characters.)
450//	   */
451//	  public PFont createFont(PApplet app, String name, float size,
452//	                          boolean smooth, char charset[]) {
453//	    String lowerName = name.toLowerCase();
454//	    Font baseFont = null;
455//
456//	    try {
457//	      InputStream stream = null;
458//	      if (lowerName.endsWith(".otf") || lowerName.endsWith(".ttf")) {
459//	        stream = app.createInput(name);
460//	        if (stream == null) {
461//	          System.err.println("The font \"" + name + "\" " +
462//	                             "is missing or inaccessible, make sure " +
463//	                             "the URL is valid or that the file has been " +
464//	                             "added to your sketch and is readable.");
465//	          return null;
466//	        }
467//	        baseFont = Font.createFont(Font.TRUETYPE_FONT, app.createInput(name));
468//
469//	      } else {
470//	        baseFont = PFont.findFont(name);
471//	      }
472//	      return new PFont(baseFont.deriveFont(size), smooth, charset, 
473//	                       stream != null);
474//
475//	    } catch (Exception e) {
476//	      System.err.println("Problem createFont(" + name + ")");
477//	      e.printStackTrace();
478//	      return null;
479//	    }
480//	  }
481//	  
482//	 private class MYPFont extends PFont{
483//		 
484//		 public void getGlyphImage(){
485//			 getGlyph('a');
486//		 }
487//		 
488//		 public class bla extends PFont.Glyph{
489//			 
490//		 }
491//		 
492//	 }
493
494
495}