Home | History | Annotate | Download | only in effects
      1 /*******************************************************************************
      2  * Copyright 2011 See AUTHORS file.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *   http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  ******************************************************************************/
     16 package com.badlogic.gdx.tools.hiero.unicodefont.effects;
     17 
     18 import java.awt.Color;
     19 import java.awt.Graphics2D;
     20 import java.awt.RenderingHints;
     21 import java.awt.geom.AffineTransform;
     22 import java.awt.image.BufferedImage;
     23 import java.util.ArrayList;
     24 import java.util.Iterator;
     25 import java.util.List;
     26 
     27 import com.badlogic.gdx.tools.distancefield.DistanceFieldGenerator;
     28 import com.badlogic.gdx.tools.hiero.unicodefont.Glyph;
     29 import com.badlogic.gdx.tools.hiero.unicodefont.UnicodeFont;
     30 
     31 /**
     32  * A filter to create a distance field. The resulting font can be rendered
     33  * with a simple custom shader to draw bitmap fonts that remain crisp
     34  * even under high magnification.
     35  *
     36  * <p> An example of the use of such a font is included in the libgdx test suite
     37  * under the name {@code BitmapFontDistanceFieldTest}.
     38  *
     39  * @see DistanceFieldGenerator
     40  *
     41  * @author Thomas ten Cate
     42  */
     43 public class DistanceFieldEffect implements ConfigurableEffect
     44 {
     45 	private Color color = Color.WHITE;
     46 	private int scale = 1;
     47 	private float spread = 1;
     48 
     49 	/**
     50 	 * Draws the glyph to the given image, upscaled by a factor of {@link #scale}.
     51 	 *
     52 	 * @param image the image to draw to
     53 	 * @param glyph the glyph to draw
     54 	 */
     55 	private void drawGlyph(BufferedImage image, Glyph glyph) {
     56 		Graphics2D inputG = (Graphics2D) image.getGraphics();
     57 		inputG.setTransform(AffineTransform.getScaleInstance(scale, scale));
     58 		// We don't really want anti-aliasing (we'll discard it anyway),
     59 		// but accurate positioning might improve the result slightly
     60 		inputG.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
     61 		inputG.setColor(Color.WHITE);
     62 		inputG.fill(glyph.getShape());
     63 	}
     64 
     65 	@Override
     66 	public void draw(BufferedImage image, Graphics2D g, UnicodeFont unicodeFont, Glyph glyph) {
     67 		BufferedImage input = new BufferedImage(
     68 			scale * glyph.getWidth(),
     69 			scale * glyph.getHeight(),
     70 			BufferedImage.TYPE_BYTE_BINARY);
     71 		drawGlyph(input, glyph);
     72 
     73 		DistanceFieldGenerator generator = new DistanceFieldGenerator();
     74 		generator.setColor(color);
     75 		generator.setDownscale(scale);
     76 		// We multiply spread by the scale, so that changing scale will only affect accuracy
     77 		// and not spread in the output image.
     78 		generator.setSpread(scale * spread);
     79 		BufferedImage distanceField = generator.generateDistanceField(input);
     80 
     81 		g.drawImage(distanceField, new AffineTransform(), null);
     82 	}
     83 
     84 	@Override
     85 	public String toString() {
     86 		return "Distance field";
     87 	}
     88 
     89 	@Override
     90 	public List getValues() {
     91 		List values = new ArrayList();
     92 		values.add(EffectUtil.colorValue("Color", color));
     93 		values.add(EffectUtil.intValue("Scale", scale, "The distance field is computed from an image larger than the output glyph by this factor. Set this to a higher value for more accuracy, but slower font generation."));
     94 		values.add(EffectUtil.floatValue("Spread", spread, 1.0f, Float.MAX_VALUE, "The maximum distance from edges where the effect of the distance field is seen. Set this to about half the width of lines in your output font."));
     95 		return values;
     96 	}
     97 
     98 	@Override
     99 	public void setValues(List values) {
    100 		for (Iterator iter = values.iterator(); iter.hasNext();) {
    101 			Value value = (Value)iter.next();
    102 			if ("Color".equals(value.getName())) {
    103 				color = (Color)value.getObject();
    104 			} else if ("Scale".equals(value.getName())) {
    105 				scale = Math.max(1, (Integer)value.getObject());
    106 			} else if ("Spread".equals(value.getName())) {
    107 				spread = Math.max(0, (Float)value.getObject());
    108 			}
    109 		}
    110 
    111 	}
    112 }