com.badlogic.gdx.tools.hiero.unicodefont.effects.DistanceFieldEffect Maven / Gradle / Ivy
/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.badlogic.gdx.tools.hiero.unicodefont.effects;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.badlogic.gdx.tools.distancefield.DistanceFieldGenerator;
import com.badlogic.gdx.tools.hiero.unicodefont.Glyph;
import com.badlogic.gdx.tools.hiero.unicodefont.UnicodeFont;
/** A filter to create a distance field. The resulting font can be rendered with a simple custom shader to draw bitmap fonts that
* remain crisp even under high magnification.
*
*
* An example of the use of such a font is included in the libgdx test suite under the name {@code BitmapFontDistanceFieldTest}.
*
* @see DistanceFieldGenerator
*
* @author Thomas ten Cate */
public class DistanceFieldEffect implements ConfigurableEffect {
private Color color = Color.WHITE;
private int scale = 1;
private float spread = 1;
/** Draws the glyph to the given image, upscaled by a factor of {@link #scale}.
*
* @param image the image to draw to
* @param glyph the glyph to draw */
private void drawGlyph (BufferedImage image, Glyph glyph) {
Graphics2D inputG = (Graphics2D)image.getGraphics();
inputG.setTransform(AffineTransform.getScaleInstance(scale, scale));
// We don't really want anti-aliasing (we'll discard it anyway),
// but accurate positioning might improve the result slightly
inputG.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
inputG.setColor(Color.WHITE);
inputG.fill(glyph.getShape());
}
@Override
public void draw (BufferedImage image, Graphics2D g, UnicodeFont unicodeFont, Glyph glyph) {
BufferedImage input = new BufferedImage(scale * glyph.getWidth(), scale * glyph.getHeight(),
BufferedImage.TYPE_BYTE_BINARY);
drawGlyph(input, glyph);
DistanceFieldGenerator generator = new DistanceFieldGenerator();
generator.setColor(color);
generator.setDownscale(scale);
// We multiply spread by the scale, so that changing scale will only affect accuracy
// and not spread in the output image.
generator.setSpread(scale * spread);
BufferedImage distanceField = generator.generateDistanceField(input);
g.drawImage(distanceField, new AffineTransform(), null);
}
@Override
public String toString () {
return "Distance field";
}
@Override
public List getValues () {
List values = new ArrayList();
values.add(EffectUtil.colorValue("Color", color));
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."));
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."));
return values;
}
@Override
public void setValues (List values) {
for (Iterator iter = values.iterator(); iter.hasNext();) {
Value value = (Value)iter.next();
if ("Color".equals(value.getName())) {
color = (Color)value.getObject();
} else if ("Scale".equals(value.getName())) {
scale = Math.max(1, (Integer)value.getObject());
} else if ("Spread".equals(value.getName())) {
spread = Math.max(0, (Float)value.getObject());
}
}
}
}