
com.badlogic.gdx.tools.hiero.unicodefont.effects.ShadowEffect Maven / Gradle / Ivy
The newest version!
/*******************************************************************************
* 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.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.badlogic.gdx.tools.hiero.unicodefont.Glyph;
import com.badlogic.gdx.tools.hiero.unicodefont.UnicodeFont;
/** @author Nathan Sweet */
public class ShadowEffect implements ConfigurableEffect {
/** The numberof kernels to apply */
public static final int NUM_KERNELS = 16;
/** The blur kernels applied across the effect */
public static final float[][] GAUSSIAN_BLUR_KERNELS = generateGaussianBlurKernels(NUM_KERNELS);
private Color color = Color.black;
private float opacity = 0.6f;
private float xDistance = 2, yDistance = 2;
private int blurKernelSize = 0;
private int blurPasses = 1;
public ShadowEffect () {
}
public ShadowEffect (Color color, int xDistance, int yDistance, float opacity) {
this.color = color;
this.xDistance = xDistance;
this.yDistance = yDistance;
this.opacity = opacity;
}
public void draw (BufferedImage image, Graphics2D g, UnicodeFont unicodeFont, Glyph glyph) {
g = (Graphics2D)g.create();
g.translate(xDistance, yDistance);
g.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), Math.round(opacity * 255)));
g.fill(glyph.getShape());
// Also shadow the outline, if one exists.
for (Iterator iter = unicodeFont.getEffects().iterator(); iter.hasNext();) {
Effect effect = (Effect)iter.next();
if (effect instanceof OutlineEffect) {
Composite composite = g.getComposite();
g.setComposite(AlphaComposite.Src); // Prevent shadow and outline shadow alpha from combining.
g.setStroke(((OutlineEffect)effect).getStroke());
g.draw(glyph.getShape());
g.setComposite(composite);
break;
}
}
g.dispose();
if (blurKernelSize > 1 && blurKernelSize < NUM_KERNELS && blurPasses > 0) blur(image);
}
private void blur (BufferedImage image) {
float[] matrix = GAUSSIAN_BLUR_KERNELS[blurKernelSize - 1];
Kernel gaussianBlur1 = new Kernel(matrix.length, 1, matrix);
Kernel gaussianBlur2 = new Kernel(1, matrix.length, matrix);
RenderingHints hints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
ConvolveOp gaussianOp1 = new ConvolveOp(gaussianBlur1, ConvolveOp.EDGE_NO_OP, hints);
ConvolveOp gaussianOp2 = new ConvolveOp(gaussianBlur2, ConvolveOp.EDGE_NO_OP, hints);
BufferedImage scratchImage = EffectUtil.getScratchImage();
for (int i = 0; i < blurPasses; i++) {
gaussianOp1.filter(image, scratchImage);
gaussianOp2.filter(scratchImage, image);
}
}
public Color getColor () {
return color;
}
public void setColor (Color color) {
this.color = color;
}
public float getXDistance () {
return xDistance;
}
/** Sets the pixels to offset the shadow on the x axis. The glyphs will need padding so the shadow doesn't get clipped. */
public void setXDistance (float distance) {
xDistance = distance;
}
public float getYDistance () {
return yDistance;
}
/** Sets the pixels to offset the shadow on the y axis. The glyphs will need padding so the shadow doesn't get clipped. */
public void setYDistance (float distance) {
yDistance = distance;
}
public int getBlurKernelSize () {
return blurKernelSize;
}
/** Sets how many neighboring pixels are used to blur the shadow. Set to 0 for no blur. */
public void setBlurKernelSize (int blurKernelSize) {
this.blurKernelSize = blurKernelSize;
}
public int getBlurPasses () {
return blurPasses;
}
/** Sets the number of times to apply a blur to the shadow. Set to 0 for no blur. */
public void setBlurPasses (int blurPasses) {
this.blurPasses = blurPasses;
}
public float getOpacity () {
return opacity;
}
public void setOpacity (float opacity) {
this.opacity = opacity;
}
public String toString () {
return "Shadow";
}
public List getValues () {
List values = new ArrayList();
values.add(EffectUtil.colorValue("Color", color));
values.add(EffectUtil.floatValue("Opacity", opacity, 0, 1, "This setting sets the translucency of the shadow."));
values.add(EffectUtil.floatValue("X distance", xDistance, -99, 99, "This setting is the amount of pixels to offset the "
+ "shadow on the x axis. The glyphs will need padding so the shadow doesn't get clipped."));
values.add(EffectUtil.floatValue("Y distance", yDistance, -99, 99, "This setting is the amount of pixels to offset the "
+ "shadow on the y axis. The glyphs will need padding so the shadow doesn't get clipped."));
List options = new ArrayList();
options.add(new String[] {"None", "0"});
for (int i = 2; i < NUM_KERNELS; i++)
options.add(new String[] {String.valueOf(i)});
String[][] optionsArray = (String[][])options.toArray(new String[options.size()][]);
values.add(EffectUtil.optionValue("Blur kernel size", String.valueOf(blurKernelSize), optionsArray,
"This setting controls how many neighboring pixels are used to blur the shadow. Set to \"None\" for no blur."));
values.add(EffectUtil.intValue("Blur passes", blurPasses,
"The setting is the number of times to apply a blur to the shadow. Set to \"0\" for no blur."));
return values;
}
public void setValues (List values) {
for (Iterator iter = values.iterator(); iter.hasNext();) {
Value value = (Value)iter.next();
if (value.getName().equals("Color")) {
color = (Color)value.getObject();
} else if (value.getName().equals("Opacity")) {
opacity = ((Float)value.getObject()).floatValue();
} else if (value.getName().equals("X distance")) {
xDistance = ((Float)value.getObject()).floatValue();
} else if (value.getName().equals("Y distance")) {
yDistance = ((Float)value.getObject()).floatValue();
} else if (value.getName().equals("Blur kernel size")) {
blurKernelSize = Integer.parseInt((String)value.getObject());
} else if (value.getName().equals("Blur passes")) {
blurPasses = ((Integer)value.getObject()).intValue();
}
}
}
/** Generate the blur kernels which will be repeatedly applied when blurring images
*
* @param level The number of kernels to generate
* @return The kernels generated */
private static float[][] generateGaussianBlurKernels (int level) {
float[][] pascalsTriangle = generatePascalsTriangle(level);
float[][] gaussianTriangle = new float[pascalsTriangle.length][];
for (int i = 0; i < gaussianTriangle.length; i++) {
float total = 0.0f;
gaussianTriangle[i] = new float[pascalsTriangle[i].length];
for (int j = 0; j < pascalsTriangle[i].length; j++)
total += pascalsTriangle[i][j];
float coefficient = 1 / total;
for (int j = 0; j < pascalsTriangle[i].length; j++)
gaussianTriangle[i][j] = coefficient * pascalsTriangle[i][j];
}
return gaussianTriangle;
}
/** Generate Pascal's triangle
*
* @param level The level of the triangle to generate
* @return The Pascal's triangle kernel */
private static float[][] generatePascalsTriangle (int level) {
if (level < 2) level = 2;
float[][] triangle = new float[level][];
triangle[0] = new float[1];
triangle[1] = new float[2];
triangle[0][0] = 1.0f;
triangle[1][0] = 1.0f;
triangle[1][1] = 1.0f;
for (int i = 2; i < level; i++) {
triangle[i] = new float[i + 1];
triangle[i][0] = 1.0f;
triangle[i][i] = 1.0f;
for (int j = 1; j < triangle[i].length - 1; j++)
triangle[i][j] = triangle[i - 1][j - 1] + triangle[i - 1][j];
}
return triangle;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy