mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-13 03:54:06 +09:00
added sources for Slick
Former-commit-id: 1647fa32ef6894bd7db44f741f07c2f4dcdf9054 Former-commit-id: 0e5810dcfbe1fd59b13e7cabe9f1e93c5542da2d
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
|
||||
package org.newdawn.slick.font.effects;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.newdawn.slick.UnicodeFont;
|
||||
import org.newdawn.slick.font.Glyph;
|
||||
|
||||
/**
|
||||
* Makes glyphs a solid color.
|
||||
*
|
||||
* @author Nathan Sweet <misc@n4te.com>
|
||||
*/
|
||||
public class ColorEffect implements ConfigurableEffect {
|
||||
/** The colour that will be applied across the text */
|
||||
private Color color = Color.white;
|
||||
|
||||
/**
|
||||
* Default constructor for injection
|
||||
*/
|
||||
public ColorEffect() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new effect to colour the text
|
||||
*
|
||||
* @param color The colour to apply across the text
|
||||
*/
|
||||
public ColorEffect(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.Effect#draw(java.awt.image.BufferedImage, java.awt.Graphics2D, org.newdawn.slick.UnicodeFont, org.newdawn.slick.font.Glyph)
|
||||
*/
|
||||
public void draw(BufferedImage image, Graphics2D g, UnicodeFont unicodeFont, Glyph glyph) {
|
||||
g.setColor(color);
|
||||
g.fill(glyph.getShape());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the colour being applied by this effect
|
||||
*
|
||||
* @return The colour being applied by this effect
|
||||
*/
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the colour being applied by this effect
|
||||
*
|
||||
* @param color The colour being applied by this effect
|
||||
*/
|
||||
public void setColor(Color color) {
|
||||
if (color == null) throw new IllegalArgumentException("color cannot be null.");
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString () {
|
||||
return "Color";
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.ConfigurableEffect#getValues()
|
||||
*/
|
||||
public List getValues() {
|
||||
List values = new ArrayList();
|
||||
values.add(EffectUtil.colorValue("Color", color));
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.ConfigurableEffect#setValues(java.util.List)
|
||||
*/
|
||||
public void setValues(List values) {
|
||||
for (Iterator iter = values.iterator(); iter.hasNext();) {
|
||||
Value value = (Value)iter.next();
|
||||
if (value.getName().equals("Color")) {
|
||||
setColor((Color)value.getObject());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
|
||||
package org.newdawn.slick.font.effects;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An effect that has a number of configuration values. This allows the effect to be configured in the Hiero GUI and to be saved
|
||||
* and loaded to and from a file.
|
||||
*
|
||||
* @author Nathan Sweet <misc@n4te.com>
|
||||
*/
|
||||
public interface ConfigurableEffect extends Effect {
|
||||
/**
|
||||
* Returns the list of {@link Value}s for this effect. This list is not typically backed by the effect, so changes to the
|
||||
* values will not take affect until {@link #setValues(List)} is called.
|
||||
*/
|
||||
public List getValues();
|
||||
|
||||
/**
|
||||
* Sets the list of {@link Value}s for this effect.
|
||||
*/
|
||||
public void setValues(List values);
|
||||
|
||||
/**
|
||||
* Represents a configurable value for an effect.
|
||||
*/
|
||||
static public interface Value {
|
||||
/**
|
||||
* Returns the name of the value.
|
||||
*/
|
||||
public String getName ();
|
||||
|
||||
/**
|
||||
* Sets the string representation of the value.
|
||||
*/
|
||||
public void setString (String value);
|
||||
|
||||
/**
|
||||
* Gets the string representation of the value.
|
||||
*/
|
||||
public String getString ();
|
||||
|
||||
/**
|
||||
* Gets the object representation of the value.
|
||||
*/
|
||||
public Object getObject ();
|
||||
|
||||
/**
|
||||
* Shows a dialog allowing a user to configure this value.
|
||||
*/
|
||||
public void showDialog ();
|
||||
}
|
||||
}
|
||||
25
lib/slick-source/org/newdawn/slick/font/effects/Effect.java
Normal file
25
lib/slick-source/org/newdawn/slick/font/effects/Effect.java
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
package org.newdawn.slick.font.effects;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import org.newdawn.slick.UnicodeFont;
|
||||
import org.newdawn.slick.font.Glyph;
|
||||
|
||||
/**
|
||||
* A graphical effect that is applied to glyphs in a {@link UnicodeFont}.
|
||||
*
|
||||
* @author Nathan Sweet <misc@n4te.com>
|
||||
*/
|
||||
public interface Effect {
|
||||
/**
|
||||
* Called to draw the effect.
|
||||
*
|
||||
* @param image The image to draw into
|
||||
* @param g The graphics context to use for applying the effect
|
||||
* @param unicodeFont The font being rendered
|
||||
* @param glyph The particular glyph being rendered
|
||||
*/
|
||||
public void draw (BufferedImage image, Graphics2D g, UnicodeFont unicodeFont, Glyph glyph);
|
||||
}
|
||||
368
lib/slick-source/org/newdawn/slick/font/effects/EffectUtil.java
Normal file
368
lib/slick-source/org/newdawn/slick/font/effects/EffectUtil.java
Normal file
@@ -0,0 +1,368 @@
|
||||
|
||||
package org.newdawn.slick.font.effects;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JColorChooser;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
|
||||
import org.newdawn.slick.font.GlyphPage;
|
||||
import org.newdawn.slick.font.effects.ConfigurableEffect.Value;
|
||||
|
||||
/**
|
||||
* Provides utility methods for effects.
|
||||
*
|
||||
* @author Nathan Sweet <misc@n4te.com>
|
||||
*/
|
||||
public class EffectUtil {
|
||||
/** A graphics 2D temporary surface to be used when generating effects */
|
||||
static private BufferedImage scratchImage = new BufferedImage(GlyphPage.MAX_GLYPH_SIZE, GlyphPage.MAX_GLYPH_SIZE,
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
/**
|
||||
* Returns an image that can be used by effects as a temp image.
|
||||
*
|
||||
* @return The scratch image used for temporary operations
|
||||
*/
|
||||
static public BufferedImage getScratchImage() {
|
||||
Graphics2D g = (Graphics2D)scratchImage.getGraphics();
|
||||
g.setComposite(AlphaComposite.Clear);
|
||||
g.fillRect(0, 0, GlyphPage.MAX_GLYPH_SIZE, GlyphPage.MAX_GLYPH_SIZE);
|
||||
g.setComposite(AlphaComposite.SrcOver);
|
||||
g.setColor(java.awt.Color.white);
|
||||
return scratchImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompts the user for a colour value
|
||||
*
|
||||
* @param name Thename of the value being configured
|
||||
* @param currentValue The default value that should be selected
|
||||
* @return The value selected
|
||||
*/
|
||||
static public Value colorValue(String name, Color currentValue) {
|
||||
return new DefaultValue(name, EffectUtil.toString(currentValue)) {
|
||||
public void showDialog () {
|
||||
Color newColor = JColorChooser.showDialog(null, "Choose a color", EffectUtil.fromString(value));
|
||||
if (newColor != null) value = EffectUtil.toString(newColor);
|
||||
}
|
||||
|
||||
public Object getObject () {
|
||||
return EffectUtil.fromString(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompts the user for int value
|
||||
*
|
||||
* @param name The name of the dialog to show
|
||||
* @param currentValue The current value to be displayed
|
||||
* @param description The help text to provide
|
||||
* @return The value selected by the user
|
||||
*/
|
||||
static public Value intValue (String name, final int currentValue, final String description) {
|
||||
return new DefaultValue(name, String.valueOf(currentValue)) {
|
||||
public void showDialog () {
|
||||
JSpinner spinner = new JSpinner(new SpinnerNumberModel(currentValue, Short.MIN_VALUE, Short.MAX_VALUE, 1));
|
||||
if (showValueDialog(spinner, description)) value = String.valueOf(spinner.getValue());
|
||||
}
|
||||
|
||||
public Object getObject () {
|
||||
return Integer.valueOf(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompts the user for float value
|
||||
*
|
||||
* @param name The name of the dialog to show
|
||||
* @param currentValue The current value to be displayed
|
||||
* @param description The help text to provide
|
||||
* @param min The minimum value to allow
|
||||
* @param max The maximum value to allow
|
||||
* @return The value selected by the user
|
||||
*/
|
||||
static public Value floatValue (String name, final float currentValue, final float min, final float max,
|
||||
final String description) {
|
||||
return new DefaultValue(name, String.valueOf(currentValue)) {
|
||||
public void showDialog () {
|
||||
JSpinner spinner = new JSpinner(new SpinnerNumberModel(currentValue, min, max, 0.1f));
|
||||
if (showValueDialog(spinner, description)) value = String.valueOf(((Double)spinner.getValue()).floatValue());
|
||||
}
|
||||
|
||||
public Object getObject () {
|
||||
return Float.valueOf(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompts the user for boolean value
|
||||
*
|
||||
* @param name The name of the dialog to show
|
||||
* @param currentValue The current value to be displayed
|
||||
* @param description The help text to provide
|
||||
* @return The value selected by the user
|
||||
*/
|
||||
static public Value booleanValue (String name, final boolean currentValue, final String description) {
|
||||
return new DefaultValue(name, String.valueOf(currentValue)) {
|
||||
public void showDialog () {
|
||||
JCheckBox checkBox = new JCheckBox();
|
||||
checkBox.setSelected(currentValue);
|
||||
if (showValueDialog(checkBox, description)) value = String.valueOf(checkBox.isSelected());
|
||||
}
|
||||
|
||||
public Object getObject () {
|
||||
return Boolean.valueOf(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prompts the user for a value that represents a fixed number of options.
|
||||
* All options are strings.
|
||||
*
|
||||
* @param options The first array has an entry for each option. Each entry is either a String[1] that is both the display value
|
||||
* and actual value, or a String[2] whose first element is the display value and second element is the actual value.
|
||||
*
|
||||
* @param name The name of the value being prompted for
|
||||
* @param currentValue The current value to show as default
|
||||
* @param description The description of the value
|
||||
* @return The value selected by the user
|
||||
*/
|
||||
static public Value optionValue (String name, final String currentValue, final String[][] options, final String description) {
|
||||
return new DefaultValue(name, currentValue.toString()) {
|
||||
public void showDialog () {
|
||||
int selectedIndex = -1;
|
||||
DefaultComboBoxModel model = new DefaultComboBoxModel();
|
||||
for (int i = 0; i < options.length; i++) {
|
||||
model.addElement(options[i][0]);
|
||||
if (getValue(i).equals(currentValue)) selectedIndex = i;
|
||||
}
|
||||
JComboBox comboBox = new JComboBox(model);
|
||||
comboBox.setSelectedIndex(selectedIndex);
|
||||
if (showValueDialog(comboBox, description)) value = getValue(comboBox.getSelectedIndex());
|
||||
}
|
||||
|
||||
private String getValue (int i) {
|
||||
if (options[i].length == 1) return options[i][0];
|
||||
return options[i][1];
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
for (int i = 0; i < options.length; i++)
|
||||
if (getValue(i).equals(value)) return options[i][0].toString();
|
||||
return "";
|
||||
}
|
||||
|
||||
public Object getObject () {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Convers a color to a string.
|
||||
*
|
||||
* @param color The color to encode to a string
|
||||
* @return The colour as a string
|
||||
*/
|
||||
static public String toString (Color color) {
|
||||
if (color == null) throw new IllegalArgumentException("color cannot be null.");
|
||||
String r = Integer.toHexString(color.getRed());
|
||||
if (r.length() == 1) r = "0" + r;
|
||||
String g = Integer.toHexString(color.getGreen());
|
||||
if (g.length() == 1) g = "0" + g;
|
||||
String b = Integer.toHexString(color.getBlue());
|
||||
if (b.length() == 1) b = "0" + b;
|
||||
return r + g + b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string to a color.
|
||||
*
|
||||
* @param rgb The string encoding the colour
|
||||
* @return The colour represented by the given encoded string
|
||||
*/
|
||||
static public Color fromString (String rgb) {
|
||||
if (rgb == null || rgb.length() != 6) return Color.white;
|
||||
return new Color(Integer.parseInt(rgb.substring(0, 2), 16), Integer.parseInt(rgb.substring(2, 4), 16), Integer.parseInt(rgb
|
||||
.substring(4, 6), 16));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides generic functionality for an effect's configurable value.
|
||||
*/
|
||||
static private abstract class DefaultValue implements Value {
|
||||
/** The value being held */
|
||||
String value;
|
||||
/** The key/name of the value */
|
||||
String name;
|
||||
|
||||
/**
|
||||
* Create a default value
|
||||
*
|
||||
* @param name The name of the value being configured
|
||||
* @param value The value to use for the default
|
||||
*/
|
||||
public DefaultValue(String name, String value) {
|
||||
this.value = value;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.ConfigurableEffect.Value#setString(java.lang.String)
|
||||
*/
|
||||
public void setString(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.ConfigurableEffect.Value#getString()
|
||||
*/
|
||||
public String getString() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.ConfigurableEffect.Value#getName()
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt the user for a value
|
||||
*
|
||||
* @param component The component to use as parent for the prompting dialog
|
||||
* @param description The description of the value being prompted for
|
||||
* @return True if the value was configured
|
||||
*/
|
||||
public boolean showValueDialog(final JComponent component, String description) {
|
||||
ValueDialog dialog = new ValueDialog(component, name, description);
|
||||
dialog.setTitle(name);
|
||||
dialog.setLocationRelativeTo(null);
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
public void run () {
|
||||
JComponent focusComponent = component;
|
||||
if (focusComponent instanceof JSpinner)
|
||||
focusComponent = ((JSpinner.DefaultEditor)((JSpinner)component).getEditor()).getTextField();
|
||||
focusComponent.requestFocusInWindow();
|
||||
}
|
||||
});
|
||||
dialog.setVisible(true);
|
||||
return dialog.okPressed;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides generic functionality for a dialog to configure a value.
|
||||
*/
|
||||
static private class ValueDialog extends JDialog {
|
||||
/** True if OK was pressed */
|
||||
public boolean okPressed = false;
|
||||
|
||||
/**
|
||||
* Create a new dialog to configure a specific value
|
||||
*
|
||||
* @param component The component to use as the parent of the dialog prompting the user
|
||||
* @param name The name of the value being configured
|
||||
* @param description The description of the value being configured
|
||||
*/
|
||||
public ValueDialog(JComponent component, String name, String description) {
|
||||
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
||||
setLayout(new GridBagLayout());
|
||||
setModal(true);
|
||||
|
||||
if (component instanceof JSpinner)
|
||||
((JSpinner.DefaultEditor)((JSpinner)component).getEditor()).getTextField().setColumns(4);
|
||||
|
||||
JPanel descriptionPanel = new JPanel();
|
||||
descriptionPanel.setLayout(new GridBagLayout());
|
||||
getContentPane().add(
|
||||
descriptionPanel,
|
||||
new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0,
|
||||
0), 0, 0));
|
||||
descriptionPanel.setBackground(Color.white);
|
||||
descriptionPanel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.black));
|
||||
{
|
||||
JTextArea descriptionText = new JTextArea(description);
|
||||
descriptionPanel.add(descriptionText, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER,
|
||||
GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0));
|
||||
descriptionText.setWrapStyleWord(true);
|
||||
descriptionText.setLineWrap(true);
|
||||
descriptionText.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
|
||||
descriptionText.setEditable(false);
|
||||
}
|
||||
|
||||
JPanel panel = new JPanel();
|
||||
getContentPane().add(
|
||||
panel,
|
||||
new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(5, 5, 0,
|
||||
5), 0, 0));
|
||||
panel.add(new JLabel(name + ":"));
|
||||
panel.add(component);
|
||||
|
||||
JPanel buttonPanel = new JPanel();
|
||||
getContentPane().add(
|
||||
buttonPanel,
|
||||
new GridBagConstraints(0, 2, 2, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE,
|
||||
new Insets(0, 0, 0, 0), 0, 0));
|
||||
{
|
||||
JButton okButton = new JButton("OK");
|
||||
buttonPanel.add(okButton);
|
||||
okButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed (ActionEvent evt) {
|
||||
okPressed = true;
|
||||
setVisible(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
{
|
||||
JButton cancelButton = new JButton("Cancel");
|
||||
buttonPanel.add(cancelButton);
|
||||
cancelButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed (ActionEvent evt) {
|
||||
setVisible(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setSize(new Dimension(320, 175));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
|
||||
package org.newdawn.slick.font.effects;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.BufferedImageOp;
|
||||
|
||||
import org.newdawn.slick.UnicodeFont;
|
||||
import org.newdawn.slick.font.Glyph;
|
||||
|
||||
/**
|
||||
* Applys a {@link BufferedImageOp} filter to glyphs. Many filters can be found
|
||||
* here: http://www.jhlabs.com/ip/filters/index.html
|
||||
*
|
||||
* @author Nathan Sweet <misc@n4te.com>
|
||||
*/
|
||||
public class FilterEffect implements Effect {
|
||||
/** The filter to be applied */
|
||||
private BufferedImageOp filter;
|
||||
|
||||
/**
|
||||
* Default constructor for injection
|
||||
*/
|
||||
public FilterEffect () {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new filtering effect based on a convolution operation
|
||||
*
|
||||
* @param filter The filter to apply
|
||||
*/
|
||||
public FilterEffect (BufferedImageOp filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.Effect#draw(java.awt.image.BufferedImage, java.awt.Graphics2D, org.newdawn.slick.UnicodeFont, org.newdawn.slick.font.Glyph)
|
||||
*/
|
||||
public void draw(BufferedImage image, Graphics2D g, UnicodeFont unicodeFont, Glyph glyph) {
|
||||
BufferedImage scratchImage = EffectUtil.getScratchImage();
|
||||
filter.filter(image, scratchImage);
|
||||
image.getGraphics().drawImage(scratchImage, 0, 0, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter being applied by this effect
|
||||
*
|
||||
* @return The filter being applied by this effect
|
||||
*/
|
||||
public BufferedImageOp getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filter being applied by this effect
|
||||
*
|
||||
* @param filter The filter being used by this effect
|
||||
*/
|
||||
public void setFilter(BufferedImageOp filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
|
||||
package org.newdawn.slick.font.effects;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.GradientPaint;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.newdawn.slick.UnicodeFont;
|
||||
import org.newdawn.slick.font.Glyph;
|
||||
|
||||
/**
|
||||
* Paints glyphs with a gradient fill.
|
||||
*
|
||||
* @author Nathan Sweet <misc@n4te.com>
|
||||
*/
|
||||
public class GradientEffect implements ConfigurableEffect {
|
||||
/** The top of gradients colour */
|
||||
private Color topColor = Color.cyan;
|
||||
/** The bottom of the gradient's colour */
|
||||
private Color bottomColor = Color.blue;
|
||||
/** The offset the gradient starts at */
|
||||
private int offset = 0;
|
||||
/** The scaling of the graident */
|
||||
private float scale = 1;
|
||||
/** True if the graident should cycle back and forth across the surface */
|
||||
private boolean cyclic;
|
||||
|
||||
/**
|
||||
* Default constructor for injection
|
||||
*/
|
||||
public GradientEffect() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new effect to apply a graident
|
||||
*
|
||||
* @param topColor The colour at the top of the graident
|
||||
* @param bottomColor The colour at the bottom of the gradient
|
||||
* @param scale The scale of the graident
|
||||
*/
|
||||
public GradientEffect(Color topColor, Color bottomColor, float scale) {
|
||||
this.topColor = topColor;
|
||||
this.bottomColor = bottomColor;
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.Effect#draw(java.awt.image.BufferedImage, java.awt.Graphics2D, org.newdawn.slick.UnicodeFont, org.newdawn.slick.font.Glyph)
|
||||
*/
|
||||
public void draw(BufferedImage image, Graphics2D g, UnicodeFont unicodeFont, Glyph glyph) {
|
||||
int ascent = unicodeFont.getAscent();
|
||||
float height = (ascent) * scale;
|
||||
float top = -glyph.getYOffset() + unicodeFont.getDescent() + offset + ascent / 2 - height / 2;
|
||||
g.setPaint(new GradientPaint(0, top, topColor, 0, top + height, bottomColor, cyclic));
|
||||
g.fill(glyph.getShape());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the colour at the top of the graident
|
||||
*
|
||||
* @return The colour at the top of the gradient
|
||||
*/
|
||||
public Color getTopColor() {
|
||||
return topColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the colour at the top of the graident
|
||||
*
|
||||
* @param topColor The colour at the top of the graident
|
||||
*/
|
||||
public void setTopColor(Color topColor) {
|
||||
this.topColor = topColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the colour at the bottom of the graident
|
||||
*
|
||||
* @return The colour at the bottom of the gradient
|
||||
*/
|
||||
public Color getBottomColor () {
|
||||
return bottomColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the colour at the bottom of the graident
|
||||
*
|
||||
* @param bottomColor The colour at the bottom of the graident
|
||||
*/
|
||||
public void setBottomColor(Color bottomColor) {
|
||||
this.bottomColor = bottomColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the offset the gradients starts at
|
||||
*
|
||||
* @return The offset the gradient starts at
|
||||
*/
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pixel offset to move the gradient up or down.
|
||||
* The gradient is normally centered on the glyph.
|
||||
*
|
||||
* @param offset The offset the gradient is moved by
|
||||
*/
|
||||
public void setOffset (int offset) {
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the percentage scaling being applied to the gradient across the surface
|
||||
*
|
||||
* @return The scale of the graident
|
||||
*/
|
||||
public float getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the height of the gradient by a percentage. The gradient is
|
||||
* normally the height of most glyphs in the font.
|
||||
*
|
||||
* @param scale The scale to apply
|
||||
*/
|
||||
public void setScale (float scale) {
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the graident is repeating
|
||||
*
|
||||
* @return True if the gradient is repeating
|
||||
*/
|
||||
public boolean isCyclic() {
|
||||
return cyclic;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to true, the gradient will repeat.
|
||||
*
|
||||
* @param cyclic True if the graident repeats
|
||||
*/
|
||||
public void setCyclic(boolean cyclic) {
|
||||
this.cyclic = cyclic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
return "Gradient";
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.ConfigurableEffect#getValues()
|
||||
*/
|
||||
public List getValues() {
|
||||
List values = new ArrayList();
|
||||
values.add(EffectUtil.colorValue("Top color", topColor));
|
||||
values.add(EffectUtil.colorValue("Bottom color", bottomColor));
|
||||
values.add(EffectUtil.intValue("Offset", offset,
|
||||
"This setting allows you to move the gradient up or down. The gradient is normally centered on the glyph."));
|
||||
values.add(EffectUtil.floatValue("Scale", scale, 0, 1, "This setting allows you to change the height of the gradient by a"
|
||||
+ "percentage. The gradient is normally the height of most glyphs in the font."));
|
||||
values.add(EffectUtil.booleanValue("Cyclic", cyclic, "If this setting is checked, the gradient will repeat."));
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.ConfigurableEffect#setValues(java.util.List)
|
||||
*/
|
||||
public void setValues(List values) {
|
||||
for (Iterator iter = values.iterator(); iter.hasNext();) {
|
||||
Value value = (Value)iter.next();
|
||||
if (value.getName().equals("Top color")) {
|
||||
topColor = (Color)value.getObject();
|
||||
} else if (value.getName().equals("Bottom color")) {
|
||||
bottomColor = (Color)value.getObject();
|
||||
} else if (value.getName().equals("Offset")) {
|
||||
offset = ((Integer)value.getObject()).intValue();
|
||||
} else if (value.getName().equals("Scale")) {
|
||||
scale = ((Float)value.getObject()).floatValue();
|
||||
} else if (value.getName().equals("Cyclic")) {
|
||||
cyclic = ((Boolean)value.getObject()).booleanValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
|
||||
package org.newdawn.slick.font.effects;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.newdawn.slick.UnicodeFont;
|
||||
import org.newdawn.slick.font.Glyph;
|
||||
|
||||
/**
|
||||
* Strokes glyphs with an outline.
|
||||
*
|
||||
* @author Nathan Sweet <misc@n4te.com>
|
||||
*/
|
||||
public class OutlineEffect implements ConfigurableEffect {
|
||||
/** The width of the outline in pixels */
|
||||
private float width = 2;
|
||||
/** The colour of the outline */
|
||||
private Color color = Color.black;
|
||||
/** The type of join at the line joins of the out line */
|
||||
private int join = BasicStroke.JOIN_BEVEL;
|
||||
/** The stroke used to draw the outline */
|
||||
private Stroke stroke;
|
||||
|
||||
/**
|
||||
* Default constructor for injection
|
||||
*/
|
||||
public OutlineEffect() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new effect to draw the outline of the text
|
||||
*
|
||||
* @param width The width of the outline
|
||||
* @param color The colour of the outline
|
||||
*/
|
||||
public OutlineEffect(int width, Color color) {
|
||||
this.width = width;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.Effect#draw(java.awt.image.BufferedImage, java.awt.Graphics2D, org.newdawn.slick.UnicodeFont, org.newdawn.slick.font.Glyph)
|
||||
*/
|
||||
public void draw(BufferedImage image, Graphics2D g, UnicodeFont unicodeFont, Glyph glyph) {
|
||||
g = (Graphics2D)g.create();
|
||||
if (stroke != null)
|
||||
g.setStroke(stroke);
|
||||
else
|
||||
g.setStroke(getStroke());
|
||||
g.setColor(color);
|
||||
g.draw(glyph.getShape());
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width of the outline being drawn
|
||||
*
|
||||
* @return The width of the outline being drawn
|
||||
*/
|
||||
public float getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the width of the outline. The glyphs will need padding so the
|
||||
* outline doesn't get clipped.
|
||||
*
|
||||
* @param width The width of the outline being drawn
|
||||
*/
|
||||
public void setWidth (int width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the colour of the outline being drawn
|
||||
*
|
||||
* @return The colour of the outline being drawn
|
||||
*/
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the colour of the outline being drawn
|
||||
*
|
||||
* @param color The colour of the outline to draw
|
||||
*/
|
||||
public void setColor(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the join type as indicated by @see BasicStroke
|
||||
*
|
||||
* @return The join type between segments in the outline
|
||||
*/
|
||||
public int getJoin() {
|
||||
return join;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stroke being used to draw the outline
|
||||
*
|
||||
* @return The stroke being used to draw the outline
|
||||
*/
|
||||
public Stroke getStroke() {
|
||||
if (stroke == null) {
|
||||
return new BasicStroke(width, BasicStroke.CAP_SQUARE, join);
|
||||
}
|
||||
|
||||
return stroke;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stroke to use for the outline. If this is set,
|
||||
* the other outline settings are ignored.
|
||||
*
|
||||
* @param stroke The stroke to be used to draw the outline
|
||||
*/
|
||||
public void setStroke (Stroke stroke) {
|
||||
this.stroke = stroke;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how the corners of the outline are drawn. This is usually only noticeable
|
||||
* at large outline widths.
|
||||
*
|
||||
* @param join One of: {@link BasicStroke#JOIN_BEVEL}, {@link BasicStroke#JOIN_MITER}, {@link BasicStroke#JOIN_ROUND}
|
||||
*/
|
||||
public void setJoin (int join) {
|
||||
this.join = join;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString () {
|
||||
return "Outline";
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.ConfigurableEffect#getValues()
|
||||
*/
|
||||
public List getValues () {
|
||||
List values = new ArrayList();
|
||||
values.add(EffectUtil.colorValue("Color", color));
|
||||
values.add(EffectUtil.floatValue("Width", width, 0.1f, 999, "This setting controls the width of the outline. "
|
||||
+ "The glyphs will need padding so the outline doesn't get clipped."));
|
||||
values.add(EffectUtil.optionValue("Join", String.valueOf(join), new String[][] { {"Bevel", BasicStroke.JOIN_BEVEL + ""},
|
||||
{"Miter", BasicStroke.JOIN_MITER + ""}, {"Round", BasicStroke.JOIN_ROUND + ""}},
|
||||
"This setting defines how the corners of the outline are drawn. "
|
||||
+ "This is usually only noticeable at large outline widths."));
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.ConfigurableEffect#setValues(java.util.List)
|
||||
*/
|
||||
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("Width")) {
|
||||
width = ((Float)value.getObject()).floatValue();
|
||||
} else if (value.getName().equals("Join")) {
|
||||
join = Integer.parseInt((String)value.getObject());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 2006 Jerry Huxtable
|
||||
*
|
||||
* 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 org.newdawn.slick.font.effects;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.geom.FlatteningPathIterator;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* An effect that genrates a wobbly line around the outline of the text
|
||||
*
|
||||
* @author Jerry Huxtable
|
||||
* @author Nathan Sweet <misc@n4te.com>
|
||||
*/
|
||||
public class OutlineWobbleEffect extends OutlineEffect {
|
||||
/** How often the line wobbles */
|
||||
private float detail = 1;
|
||||
/** The amount of the line wobbles */
|
||||
private float amplitude = 1;
|
||||
|
||||
/**
|
||||
* Default constructor for injection
|
||||
*/
|
||||
public OutlineWobbleEffect () {
|
||||
setStroke(new WobbleStroke());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the detail of the wobble effect.
|
||||
*
|
||||
* @return The detail of the wobble effect
|
||||
*/
|
||||
public float getDetail() {
|
||||
return detail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the detail of the wobble effect.
|
||||
*
|
||||
* @param detail The detail of the wobble effect
|
||||
*/
|
||||
public void setDetail(float detail) {
|
||||
this.detail = detail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the amplitude of the wobble effect.
|
||||
*
|
||||
* @return The amplitude of the wobble effect
|
||||
*/
|
||||
public float getAmplitude() {
|
||||
return amplitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the amplitude of the wobble effect.
|
||||
*
|
||||
* @param amplitude The detail of the wobble effect
|
||||
*/
|
||||
public void setAmplitude(float amplitude) {
|
||||
this.amplitude = amplitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new effect that generates a wobbly line around the text
|
||||
*
|
||||
* @param width The width of the line
|
||||
* @param color The colour of the line
|
||||
*/
|
||||
public OutlineWobbleEffect (int width, Color color) {
|
||||
super(width, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.OutlineEffect#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
return "Outline (Wobble)";
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.OutlineEffect#getValues()
|
||||
*/
|
||||
public List getValues() {
|
||||
List values = super.getValues();
|
||||
values.remove(2); // Remove "Join".
|
||||
values.add(EffectUtil.floatValue("Detail", detail, 1, 50, "This setting controls how detailed the outline will be. "
|
||||
+ "Smaller numbers cause the outline to have more detail."));
|
||||
values.add(EffectUtil.floatValue("Amplitude", amplitude, 0.5f, 50, "This setting controls the amplitude of the outline."));
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.OutlineEffect#setValues(java.util.List)
|
||||
*/
|
||||
public void setValues(List values) {
|
||||
super.setValues(values);
|
||||
for (Iterator iter = values.iterator(); iter.hasNext();) {
|
||||
Value value = (Value)iter.next();
|
||||
if (value.getName().equals("Detail")) {
|
||||
detail = ((Float)value.getObject()).floatValue();
|
||||
} else if (value.getName().equals("Amplitude")) {
|
||||
amplitude = ((Float)value.getObject()).floatValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A stroke that generate a wobbly line
|
||||
*
|
||||
* @author Jerry Huxtable
|
||||
* @author Nathan Sweet <misc@n4te.com>
|
||||
*/
|
||||
private class WobbleStroke implements Stroke {
|
||||
/** The flattening factor of the stroke */
|
||||
private static final float FLATNESS = 1;
|
||||
|
||||
/**
|
||||
* @see java.awt.Stroke#createStrokedShape(java.awt.Shape)
|
||||
*/
|
||||
public Shape createStrokedShape (Shape shape) {
|
||||
GeneralPath result = new GeneralPath();
|
||||
shape = new BasicStroke(getWidth(), BasicStroke.CAP_SQUARE, getJoin()).createStrokedShape(shape);
|
||||
PathIterator it = new FlatteningPathIterator(shape.getPathIterator(null), FLATNESS);
|
||||
float points[] = new float[6];
|
||||
float moveX = 0, moveY = 0;
|
||||
float lastX = 0, lastY = 0;
|
||||
float thisX = 0, thisY = 0;
|
||||
int type = 0;
|
||||
float next = 0;
|
||||
while (!it.isDone()) {
|
||||
type = it.currentSegment(points);
|
||||
switch (type) {
|
||||
case PathIterator.SEG_MOVETO:
|
||||
moveX = lastX = randomize(points[0]);
|
||||
moveY = lastY = randomize(points[1]);
|
||||
result.moveTo(moveX, moveY);
|
||||
next = 0;
|
||||
break;
|
||||
|
||||
case PathIterator.SEG_CLOSE:
|
||||
points[0] = moveX;
|
||||
points[1] = moveY;
|
||||
// Fall into....
|
||||
|
||||
case PathIterator.SEG_LINETO:
|
||||
thisX = randomize(points[0]);
|
||||
thisY = randomize(points[1]);
|
||||
float dx = thisX - lastX;
|
||||
float dy = thisY - lastY;
|
||||
float distance = (float)Math.sqrt(dx * dx + dy * dy);
|
||||
if (distance >= next) {
|
||||
float r = 1.0f / distance;
|
||||
while (distance >= next) {
|
||||
float x = lastX + next * dx * r;
|
||||
float y = lastY + next * dy * r;
|
||||
result.lineTo(randomize(x), randomize(y));
|
||||
next += detail;
|
||||
}
|
||||
}
|
||||
next -= distance;
|
||||
lastX = thisX;
|
||||
lastY = thisY;
|
||||
break;
|
||||
}
|
||||
it.next();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random wobble factor
|
||||
*
|
||||
* @param x The position on the line
|
||||
* @return The wobble factor
|
||||
*/
|
||||
private float randomize(float x) {
|
||||
return x + (float)Math.random() * amplitude * 2 - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright 2006 Jerry Huxtable
|
||||
*
|
||||
* 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 org.newdawn.slick.font.effects;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.geom.FlatteningPathIterator;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* An effect to generate a uniformly zigzaging line around text
|
||||
*
|
||||
* @author Jerry Huxtable
|
||||
* @author Nathan Sweet <misc@n4te.com>
|
||||
*/
|
||||
public class OutlineZigzagEffect extends OutlineEffect {
|
||||
/** The amount the line moves away from the text */
|
||||
private float amplitude = 1;
|
||||
/** How often the line zigs and zags */
|
||||
private float wavelength = 3;
|
||||
|
||||
/**
|
||||
* Default constructor for injection
|
||||
*/
|
||||
public OutlineZigzagEffect() {
|
||||
setStroke(new ZigzagStroke());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the wavelength of the wobble effect.
|
||||
*
|
||||
* @return The wavelength of the wobble effect
|
||||
*/
|
||||
public float getWavelength() {
|
||||
return wavelength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the wavelength of the wobble effect.
|
||||
*
|
||||
* @param wavelength The wavelength of the wobble effect
|
||||
*/
|
||||
public void setWavelength(float wavelength) {
|
||||
this.wavelength = wavelength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the amplitude of the wobble effect.
|
||||
*
|
||||
* @return The amplitude of the wobble effect
|
||||
*/
|
||||
public float getAmplitude() {
|
||||
return amplitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the amplitude of the wobble effect.
|
||||
*
|
||||
* @param amplitude The detail of the wobble effect
|
||||
*/
|
||||
public void setAmplitude(float amplitude) {
|
||||
this.amplitude = amplitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new effect to generate a zigzagging line around the text
|
||||
*
|
||||
* @param width The width of the line
|
||||
* @param color The colour of the line
|
||||
*/
|
||||
public OutlineZigzagEffect(int width, Color color) {
|
||||
super(width, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.OutlineEffect#toString()
|
||||
*/
|
||||
public String toString () {
|
||||
return "Outline (Zigzag)";
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.OutlineEffect#getValues()
|
||||
*/
|
||||
public List getValues() {
|
||||
List values = super.getValues();
|
||||
values.add(EffectUtil.floatValue("Wavelength", wavelength, 1, 100, "This setting controls the wavelength of the outline. "
|
||||
+ "The smaller the value, the more segments will be used to draw the outline."));
|
||||
values.add(EffectUtil.floatValue("Amplitude", amplitude, 0.5f, 50, "This setting controls the amplitude of the outline. "
|
||||
+ "The bigger the value, the more the zigzags will vary."));
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.OutlineEffect#setValues(java.util.List)
|
||||
*/
|
||||
public void setValues(List values) {
|
||||
super.setValues(values);
|
||||
for (Iterator iter = values.iterator(); iter.hasNext();) {
|
||||
Value value = (Value)iter.next();
|
||||
if (value.getName().equals("Wavelength")) {
|
||||
wavelength = ((Float)value.getObject()).floatValue();
|
||||
} else if (value.getName().equals("Amplitude")) {
|
||||
amplitude = ((Float)value.getObject()).floatValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A stroke to generate zigzags
|
||||
*
|
||||
* @author Jerry Huxtable
|
||||
* @author Nathan Sweet <misc@n4te.com>
|
||||
*/
|
||||
private class ZigzagStroke implements Stroke {
|
||||
/** The flattening factor applied to the path iterator */
|
||||
private static final float FLATNESS = 1;
|
||||
|
||||
/**
|
||||
* @see java.awt.Stroke#createStrokedShape(java.awt.Shape)
|
||||
*/
|
||||
public Shape createStrokedShape (Shape shape) {
|
||||
GeneralPath result = new GeneralPath();
|
||||
PathIterator it = new FlatteningPathIterator(shape.getPathIterator(null), FLATNESS);
|
||||
float points[] = new float[6];
|
||||
float moveX = 0, moveY = 0;
|
||||
float lastX = 0, lastY = 0;
|
||||
float thisX = 0, thisY = 0;
|
||||
int type = 0;
|
||||
float next = 0;
|
||||
int phase = 0;
|
||||
while (!it.isDone()) {
|
||||
type = it.currentSegment(points);
|
||||
switch (type) {
|
||||
case PathIterator.SEG_MOVETO:
|
||||
moveX = lastX = points[0];
|
||||
moveY = lastY = points[1];
|
||||
result.moveTo(moveX, moveY);
|
||||
next = wavelength / 2;
|
||||
break;
|
||||
|
||||
case PathIterator.SEG_CLOSE:
|
||||
points[0] = moveX;
|
||||
points[1] = moveY;
|
||||
// Fall into....
|
||||
|
||||
case PathIterator.SEG_LINETO:
|
||||
thisX = points[0];
|
||||
thisY = points[1];
|
||||
float dx = thisX - lastX;
|
||||
float dy = thisY - lastY;
|
||||
float distance = (float)Math.sqrt(dx * dx + dy * dy);
|
||||
if (distance >= next) {
|
||||
float r = 1.0f / distance;
|
||||
while (distance >= next) {
|
||||
float x = lastX + next * dx * r;
|
||||
float y = lastY + next * dy * r;
|
||||
if ((phase & 1) == 0)
|
||||
result.lineTo(x + amplitude * dy * r, y - amplitude * dx * r);
|
||||
else
|
||||
result.lineTo(x - amplitude * dy * r, y + amplitude * dx * r);
|
||||
next += wavelength;
|
||||
phase++;
|
||||
}
|
||||
}
|
||||
next -= distance;
|
||||
lastX = thisX;
|
||||
lastY = thisY;
|
||||
if (type == PathIterator.SEG_CLOSE) result.closePath();
|
||||
break;
|
||||
}
|
||||
it.next();
|
||||
}
|
||||
return new BasicStroke(getWidth(), BasicStroke.CAP_SQUARE, getJoin()).createStrokedShape(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
|
||||
package org.newdawn.slick.font.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 org.newdawn.slick.UnicodeFont;
|
||||
import org.newdawn.slick.font.Glyph;
|
||||
|
||||
/**
|
||||
* An effect to generate soft shadows beneath text
|
||||
*
|
||||
* @author Nathan Sweet <misc@n4te.com>
|
||||
*/
|
||||
public class ShadowEffect implements ConfigurableEffect {
|
||||
/** The number of 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);
|
||||
|
||||
/** The colour of the shadow to render */
|
||||
private Color color = Color.black;
|
||||
/** The transparency factor of the shadow */
|
||||
private float opacity = 0.6f;
|
||||
/** The distance on the x axis of the shadow from the text */
|
||||
private float xDistance = 2;
|
||||
/** The distance on the y axis of the shadow from the text */
|
||||
private float yDistance = 2;
|
||||
/** The size of the kernel used to blur the shadow */
|
||||
private int blurKernelSize = 0;
|
||||
/** The number of passes applied to create the blur */
|
||||
private int blurPasses = 1;
|
||||
|
||||
/**
|
||||
* Default constructor for injection
|
||||
*/
|
||||
public ShadowEffect() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new effect to apply a drop shadow to text
|
||||
*
|
||||
* @param color The colour of the shadow to generate
|
||||
* @param xDistance The distance from the text on the x axis the shadow should be rendered
|
||||
* @param yDistance The distance from the text on the y axis the shadow should be rendered
|
||||
* @param opacity The transparency factor of the shadow
|
||||
*/
|
||||
public ShadowEffect (Color color, int xDistance, int yDistance, float opacity) {
|
||||
this.color = color;
|
||||
this.xDistance = xDistance;
|
||||
this.yDistance = yDistance;
|
||||
this.opacity = opacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.Effect#draw(java.awt.image.BufferedImage, java.awt.Graphics2D, org.newdawn.slick.UnicodeFont, org.newdawn.slick.font.Glyph)
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply blurring to the generate image
|
||||
*
|
||||
* @param image The image to be blurred
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the colour of the shadow generated
|
||||
*
|
||||
* @return The colour of the shadow generated
|
||||
*/
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the colour of the shadow to be generated
|
||||
*
|
||||
* @param color The colour ofthe shadow to be generated
|
||||
*/
|
||||
public void setColor(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance on the X axis from the text the shadow should
|
||||
* be generated at
|
||||
*
|
||||
* @return The distance on the X axis the shadow will be from the text
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param distance The offset on the x axis
|
||||
*/
|
||||
public void setXDistance(float distance) {
|
||||
xDistance = distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance on the Y axis from the text the shadow should
|
||||
* be generated at
|
||||
*
|
||||
* @return The distance on the Y axis the shadow will be from the text
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param distance The offset on the y axis
|
||||
*/
|
||||
public void setYDistance (float distance) {
|
||||
yDistance = distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of the kernel used to apply the blur
|
||||
*
|
||||
* @return The blur kernel size
|
||||
*/
|
||||
public int getBlurKernelSize() {
|
||||
return blurKernelSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how many neighboring pixels are used to blur the shadow. Set to 0 for no blur.
|
||||
*
|
||||
* @param blurKernelSize The size of the kernel to apply the blur with
|
||||
*/
|
||||
public void setBlurKernelSize (int blurKernelSize) {
|
||||
this.blurKernelSize = blurKernelSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of passes to apply the kernel for blurring
|
||||
*
|
||||
* @return The number of passes
|
||||
*/
|
||||
public int getBlurPasses() {
|
||||
return blurPasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of times to apply a blur to the shadow. Set to 0 for no blur.
|
||||
*
|
||||
* @param blurPasses The number of passes to apply when blurring
|
||||
*/
|
||||
public void setBlurPasses (int blurPasses) {
|
||||
this.blurPasses = blurPasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the opacity of the shadow, i.e. how transparent it is
|
||||
*
|
||||
* @return The opacity of the shadow
|
||||
*/
|
||||
public float getOpacity() {
|
||||
return opacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the opacity of the shadow, i.e. how transparent it is
|
||||
*
|
||||
* @param opacity The opacity of the shadow
|
||||
*/
|
||||
public void setOpacity(float opacity) {
|
||||
this.opacity = opacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
return "Shadow";
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.ConfigurableEffect#getValues()
|
||||
*/
|
||||
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, Float.MIN_VALUE, Float.MAX_VALUE, "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, Float.MIN_VALUE, Float.MAX_VALUE, "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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.newdawn.slick.font.effects.ConfigurableEffect#setValues(java.util.List)
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user