blob: 9cf2aabf48540dfbbb3040bd306044b3165672c3 [file] [log] [blame]
/*
*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package java2d;
import static java.awt.Color.BLACK;
import static java.awt.Color.GRAY;
import static java.awt.Color.RED;
import static java.awt.Color.WHITE;
import static java.awt.Color.YELLOW;
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.TexturePaint;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.FlatteningPathIterator;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTable;
import javax.swing.border.BevelBorder;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.TableModelEvent;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
/**
* Introduction to the J2Ddemo.
*
* @author Brian Lichtenwalter
* @author Alexander Kouznetsov
*/
@SuppressWarnings("serial")
public class Intro extends JPanel {
private static final Color myBlack = new Color(20, 20, 20);
private static final Color myWhite = new Color(240, 240, 255);
private static final Color myRed = new Color(149, 43, 42);
private static final Color myBlue = new Color(94, 105, 176);
private static final Color myYellow = new Color(255, 255, 140);
private ScenesTable scenesTable;
private boolean doTable;
private final Surface surface;
public Intro() {
EmptyBorder eb = new EmptyBorder(80, 110, 80, 110);
BevelBorder bb = new BevelBorder(BevelBorder.LOWERED);
setBorder(new CompoundBorder(eb, bb));
setLayout(new BorderLayout());
setBackground(GRAY);
setToolTipText("click for scene table");
add(surface = new Surface());
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
removeAll();
if ((doTable = !doTable)) {
setToolTipText("click for animation");
surface.stop();
if (scenesTable == null) {
scenesTable = new ScenesTable(Intro.this);
}
add(scenesTable);
} else {
setToolTipText("click for scene table");
surface.start();
add(surface);
}
revalidate();
repaint();
}
});
}
public void start() {
if (!doTable) {
surface.start();
}
}
public void stop() {
if (!doTable) {
surface.stop();
}
}
public static void main(String argv[]) {
final Intro intro = new Intro();
WindowListener l = new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
@Override
public void windowDeiconified(WindowEvent e) {
intro.start();
}
@Override
public void windowIconified(WindowEvent e) {
intro.stop();
}
};
JFrame f = new JFrame("Java2D(TM) Demo - Intro");
f.addWindowListener(l);
f.getContentPane().add("Center", intro);
f.pack();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int w = 720;
int h = 510;
f.setLocation(screenSize.width / 2 - w / 2, screenSize.height / 2 - h
/ 2);
f.setSize(w, h);
f.setVisible(true);
intro.start();
}
/**
* ScenesTable is the list of scenes known to the Director.
* Scene participation, scene name and scene pause amount columns.
* Global animation delay for scene's steps.
*/
static class ScenesTable extends JPanel implements ActionListener,
ChangeListener {
private final Intro intro;
private JTable table;
private TableModel dataModel;
@SuppressWarnings("LeakingThisInConstructor")
public ScenesTable(final Intro intro) {
this.intro = intro;
setBackground(WHITE);
setLayout(new BorderLayout());
final String[] names = { "", "Scenes", "Pause" };
dataModel = new AbstractTableModel() {
@Override
public int getColumnCount() {
return names.length;
}
@Override
public int getRowCount() {
return intro.surface.director.size();
}
@Override
public Object getValueAt(int row, int col) {
Surface.Scene scene = intro.surface.director.get(row);
if (col == 0) {
return scene.participate;
} else if (col == 1) {
return scene.name;
} else {
return scene.pauseAmt;
}
}
@Override
public String getColumnName(int col) {
return names[col];
}
@Override
public Class<?> getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
@Override
public boolean isCellEditable(int row, int col) {
return col != 1 ? true : false;
}
@Override
public void setValueAt(Object aValue, int row, int col) {
Surface.Scene scene = intro.surface.director.get(row);
if (col == 0) {
scene.participate = aValue;
} else if (col == 1) {
scene.name = aValue;
} else {
scene.pauseAmt = aValue;
}
}
};
table = new JTable(dataModel);
TableColumn col = table.getColumn("");
col.setWidth(16);
col.setMinWidth(16);
col.setMaxWidth(20);
col = table.getColumn("Pause");
col.setWidth(60);
col.setMinWidth(60);
col.setMaxWidth(60);
table.sizeColumnsToFit(0);
JScrollPane scrollpane = new JScrollPane(table);
add(scrollpane);
JPanel panel = new JPanel(new BorderLayout());
JButton b = new JButton("Unselect All");
b.setHorizontalAlignment(JButton.LEFT);
Font font = new Font(Font.SERIF, Font.PLAIN, 10);
b.setFont(font);
b.addActionListener(this);
panel.add("West", b);
JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 200,
(int) intro.surface.sleepAmt);
slider.addChangeListener(this);
TitledBorder tb = new TitledBorder(new EtchedBorder());
tb.setTitleFont(font);
tb.setTitle("Anim delay = " + String.valueOf(intro.surface.sleepAmt)
+ " ms");
slider.setBorder(tb);
slider.setPreferredSize(new Dimension(140, 40));
slider.setMinimumSize(new Dimension(100, 40));
slider.setMaximumSize(new Dimension(180, 40));
panel.add("East", slider);
add("South", panel);
}
@Override
public void actionPerformed(ActionEvent e) {
JButton b = (JButton) e.getSource();
b.setSelected(!b.isSelected());
b.setText(b.isSelected() ? "Select All" : "Unselect All");
for (int i = 0; i < intro.surface.director.size(); i++) {
Surface.Scene scene = intro.surface.director.get(i);
scene.participate = Boolean.valueOf(!b.isSelected());
}
table.tableChanged(new TableModelEvent(dataModel));
}
@Override
public void stateChanged(ChangeEvent e) {
JSlider slider = (JSlider) e.getSource();
int value = slider.getValue();
TitledBorder tb = (TitledBorder) slider.getBorder();
tb.setTitle("Anim delay = " + String.valueOf(value) + " ms");
intro.surface.sleepAmt = (long) value;
slider.repaint();
}
} // End ScenesTable class
/**
* Surface is the stage where the Director plays its scenes.
*/
static class Surface extends JPanel implements Runnable {
private final Image dukeanim, duke;
private BufferedImage bimg;
public Director director;
public int index;
public long sleepAmt = 30;
private Thread thread;
@SuppressWarnings("LeakingThisInConstructor")
public Surface() {
setBackground(myBlack);
setLayout(new BorderLayout());
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (thread == null) {
start();
} else {
stop();
}
}
});
dukeanim = DemoImages.getImage("duke.running.gif", this);
duke = DemoImages.getImage("duke.png", this);
director = new Director(this);
}
public FontMetrics getMetrics(Font font) {
return getFontMetrics(font);
}
@Override
public void paint(Graphics g) {
Dimension d = getSize();
if (d.width <= 0 || d.height <= 0) {
return;
}
if (bimg == null || bimg.getWidth() != d.width || bimg.getHeight()
!= d.height) {
bimg = getGraphicsConfiguration().createCompatibleImage(d.width,
d.height);
// reset future scenes
for (int i = index + 1; i < director.size(); i++) {
(director.get(i)).reset(d.width, d.height);
}
}
Scene scene = director.get(index);
if (scene.index <= scene.length) {
if (thread != null) {
scene.step(d.width, d.height);
}
Graphics2D g2 = bimg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setBackground(getBackground());
g2.clearRect(0, 0, d.width, d.height);
scene.render(d.width, d.height, g2);
if (thread != null) {
// increment scene.index after scene.render
scene.index++;
}
g2.dispose();
}
g.drawImage(bimg, 0, 0, this);
}
public void start() {
if (thread == null) {
thread = new Thread(this);
thread.setPriority(Thread.MIN_PRIORITY);
thread.setName("Intro");
thread.start();
}
}
public synchronized void stop() {
if (thread != null) {
thread.interrupt();
}
thread = null;
notifyAll();
}
public void reset() {
index = 0;
Dimension d = getSize();
for (Scene scene : director) {
scene.reset(d.width, d.height);
}
}
@Override
@SuppressWarnings("SleepWhileHoldingLock")
public void run() {
Thread me = Thread.currentThread();
while (thread == me && !isShowing() || getSize().width <= 0) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
return;
}
}
if (index == 0) {
reset();
}
while (thread == me) {
Scene scene = director.get(index);
if (((Boolean) scene.participate).booleanValue()) {
repaint();
try {
Thread.sleep(sleepAmt);
} catch (InterruptedException e) {
break;
}
if (scene.index > scene.length) {
scene.pause();
if (++index >= director.size()) {
reset();
}
}
} else {
if (++index >= director.size()) {
reset();
}
}
}
thread = null;
}
/**
* Part is a piece of the scene. Classes must implement Part
* in order to participate in a scene.
*/
interface Part {
public void reset(int newwidth, int newheight);
public void step(int w, int h);
public void render(int w, int h, Graphics2D g2);
public int getBegin();
public int getEnd();
}
/**
* Director is the holder of the scenes, their names & pause amounts
* between scenes.
*/
static class Director extends ArrayList<Scene> {
GradientPaint gp = new GradientPaint(0, 40, myBlue, 38, 2, myBlack);
Font f1 = new Font(Font.SERIF, Font.PLAIN, 200);
Font f2 = new Font(Font.SERIF, Font.PLAIN, 120);
Font f3 = new Font(Font.SERIF, Font.PLAIN, 72);
public Director(Surface surf) {
Object partsInfo[][][] = {
{ { "J - scale text on gradient", "0" },
{ new GpE(GpE.BURI, myBlack, myBlue, 0, 20),
new TxE("J", f1, TxE.SCI, myYellow, 2, 20) } },
{ { "2 - scale & rotate text on gradient", "0" },
{ new GpE(GpE.BURI, myBlue, myBlack, 0, 22),
new TxE("2", f1, TxE.RI | TxE.SCI, myYellow, 2, 22) } },
{ { "D - scale text on gradient", "0" },
{ new GpE(GpE.BURI, myBlack, myBlue, 0, 20),
new TxE("D", f1, TxE.SCI, myYellow, 2, 20) } },
{ { "J2D demo - scale & rotate text on gradient", "1000" },
{ new GpE(GpE.SIH, myBlue, myBlack, 0, 40),
new TxE("J2D demo", f2, TxE.RI | TxE.SCI, myYellow, 0, 40) } },
{ { "Previous scene dither dissolve out", "0" },
{ new DdE(0, 20, 1, surf) } },
{ { "Graphics Features", "999" },
{ new Temp(Temp.RECT, null, 0, 15),
new Temp(Temp.IMG, surf.duke, 2, 15),
new Temp(Temp.RNA | Temp.INA, surf.duke, 16, 130),
new Features(Features.GRAPHICS, 16, 130, surf) } },
{ { "J2D demo - texture text on gradient", "1000" },
{ new GpE(GpE.WI, myBlue, myBlack, 0, 20),
new GpE(GpE.WD, myBlue, myBlack, 21, 40),
new TpE(TpE.OI | TpE.NF, myBlack, myYellow, 4, 0, 10),
new TpE(TpE.OD | TpE.NF, myBlack, myYellow, 4, 11, 20),
new TpE(TpE.OI | TpE.NF | TpE.HAF, myBlack, myYellow, 5,
21, 40),
new TxE("J2D demo", f2, 0, null, 0, 40) } },
{ { "Previous scene random close out", "0" },
{ new CoE(CoE.RAND, 0, 20, surf) } },
{ { "Text Features", "999" },
{ new Temp(Temp.RECT, null, 0, 15),
new Temp(Temp.IMG, surf.duke, 2, 15),
new Temp(Temp.RNA | Temp.INA, surf.duke, 16, 130),
new Features(Features.TEXT, 16, 130, surf) } },
{ { "J2D demo - composite text on texture", "1000" },
{ new TpE(TpE.RI, myBlack, gp, 40, 0, 20),
new TpE(TpE.RD, myBlack, gp, 40, 21, 40),
new TpE(TpE.RI, myBlack, gp, 40, 41, 60),
new TxE("J2D demo", f2, TxE.AC, myYellow, 0, 60) } },
{ { "Previous scene dither dissolve out", "0" },
{ new DdE(0, 20, 4, surf) } },
{ { "Imaging Features", "999" },
{ new Temp(Temp.RECT, null, 0, 15),
new Temp(Temp.IMG, surf.duke, 2, 15),
new Temp(Temp.RNA | Temp.INA, surf.duke, 16, 130),
new Features(Features.IMAGES, 16, 130, surf) } },
{ { "J2D demo - text on gradient", "1000" },
{ new GpE(GpE.SDH, myBlue, myBlack, 0, 20),
new GpE(GpE.SIH, myBlue, myBlack, 21, 40),
new GpE(GpE.SDH, myBlue, myBlack, 41, 50),
new GpE(GpE.INC | GpE.NF, myRed, myYellow, 0, 50),
new TxE("J2D demo", f2, TxE.NOP, null, 0, 50) } },
{ { "Previous scene ellipse close out", "0" },
{ new CoE(CoE.OVAL, 0, 20, surf) } },
{ { "Color Features", "999" },
{ new Temp(Temp.RECT, null, 0, 15),
new Temp(Temp.IMG, surf.duke, 2, 15),
new Temp(Temp.RNA | Temp.INA, surf.duke, 16, 99),
new Features(Features.COLOR, 16, 99, surf) } },
{ { "J2D demo - composite and rotate text on paints", "2000" },
{ new GpE(GpE.BURI, myBlack, myBlue, 0, 20),
new GpE(GpE.BURD, myBlack, myBlue, 21, 30),
new TpE(TpE.OI | TpE.HAF, myBlack, myBlue, 10, 31, 40),
new TxE("J2D demo", f2, TxE.AC | TxE.RI, myYellow, 0, 40) } },
{ { "Previous scene subimage transform out", "0" },
{ new SiE(60, 60, 0, 40, surf) } },
{ { "CREDITS - transform in", "1000" },
{ new LnE(LnE.ACI | LnE.ZOOMI | LnE.RI, 0, 60),
new TxE("CREDITS", f3, TxE.AC | TxE.SCI, RED, 20, 30),
new TxE("CREDITS", f3, TxE.SCXD, RED, 31, 38),
new TxE("CREDITS", f3, TxE.SCXI, RED, 39, 48),
new TxE("CREDITS", f3, TxE.SCXD, RED, 49, 54),
new TxE("CREDITS", f3, TxE.SCXI, RED, 55, 60) } },
{ { "CREDITS - transform out", "0" },
{ new LnE(LnE.ACD | LnE.ZOOMD | LnE.RD, 0, 45),
new TxE("CREDITS", f3, 0, RED, 0, 9),
new TxE("CREDITS", f3, TxE.SCD | TxE.RD, RED, 10, 30) } },
{ { "Contributors", "1000" },
{ new Temp(Temp.RECT, null, 0, 30),
new Temp(Temp.IMG, surf.dukeanim, 4, 30),
new Temp(Temp.RNA | Temp.INA, surf.dukeanim, 31, 200),
new Contributors(34, 200, surf) } }, };
for (Object[][] partInfo : partsInfo) {
List<Part> parts = new ArrayList<Part>();
for (Object part : partInfo[1]) {
parts.add((Part) part);
}
add(new Scene(parts, partInfo[0][0], partInfo[0][1]));
}
}
}
/**
* Scene is the manager of the parts.
*/
static class Scene extends Object {
public Object name;
public Object participate = Boolean.TRUE;
public Object pauseAmt;
public List<Part> parts;
public int index;
public int length;
public Scene(List<Part> parts, Object name, Object pauseAmt) {
this.name = name;
this.parts = parts;
this.pauseAmt = pauseAmt;
for (Part part : parts) {
int partLength = part.getEnd();
if (partLength > length) {
length = partLength;
}
}
}
public void reset(int w, int h) {
index = 0;
for (int i = 0; i < parts.size(); i++) {
(parts.get(i)).reset(w, h);
}
}
public void step(int w, int h) {
for (int i = 0; i < parts.size(); i++) {
Part part = parts.get(i);
if (index >= part.getBegin() && index <= part.getEnd()) {
part.step(w, h);
}
}
}
public void render(int w, int h, Graphics2D g2) {
for (int i = 0; i < parts.size(); i++) {
Part part = parts.get(i);
if (index >= part.getBegin() && index <= part.getEnd()) {
part.render(w, h, g2);
}
}
}
public void pause() {
try {
Thread.sleep(Long.parseLong((String) pauseAmt));
} catch (Exception ignored) {
}
System.gc();
}
} // End Scene class
/**
* Text Effect. Transformation of characters. Clip or fill.
*/
static final class TxE implements Part {
static final int INC = 1;
static final int DEC = 2;
static final int R = 4; // rotate
static final int RI = R | INC;
static final int RD = R | DEC;
static final int SC = 8; // scale
static final int SCI = SC | INC;
static final int SCD = SC | DEC;
static final int SCX = 16; // scale invert x
static final int SCXI = SCX | SC | INC;
static final int SCXD = SCX | SC | DEC;
static final int SCY = 32; // scale invert y
static final int SCYI = SCY | SC | INC;
static final int SCYD = SCY | SC | DEC;
static final int AC = 64; // AlphaComposite
static final int CLIP = 128; // Clipping
static final int NOP = 512; // No Paint
private int beginning, ending;
private int type;
private double rIncr, sIncr;
private double sx, sy, rotate;
private Shape shapes[], txShapes[];
private int sw;
private int numRev;
private Paint paint;
public TxE(String text,
Font font,
int type,
Paint paint,
int beg,
int end) {
this.type = type;
this.paint = paint;
this.beginning = beg;
this.ending = end;
setIncrements(2);
char[] chars = text.toCharArray();
shapes = new Shape[chars.length];
txShapes = new Shape[chars.length];
FontRenderContext frc = new FontRenderContext(null, true, true);
TextLayout tl = new TextLayout(text, font, frc);
sw = (int) tl.getOutline(null).getBounds().getWidth();
for (int j = 0; j < chars.length; j++) {
String s = String.valueOf(chars[j]);
shapes[j] = new TextLayout(s, font, frc).getOutline(null);
}
}
public void setIncrements(double numRevolutions) {
this.numRev = (int) numRevolutions;
rIncr = 360.0 / ((ending - beginning) / numRevolutions);
sIncr = 1.0 / (ending - beginning);
if ((type & SCX) != 0 || (type & SCY) != 0) {
sIncr *= 2;
}
if ((type & DEC) != 0) {
rIncr = -rIncr;
sIncr = -sIncr;
}
}
@Override
public void reset(int w, int h) {
if (type == SCXI) {
sx = -1.0;
sy = 1.0;
} else if (type == SCYI) {
sx = 1.0;
sy = -1.0;
} else {
sx = sy = (type & DEC) != 0 ? 1.0 : 0.0;
}
rotate = 0;
}
@Override
public void step(int w, int h) {
float charWidth = w / 2 - sw / 2;
for (int i = 0; i < shapes.length; i++) {
AffineTransform at = new AffineTransform();
Rectangle2D maxBounds = shapes[i].getBounds();
at.translate(charWidth, h / 2 + maxBounds.getHeight() / 2);
charWidth += (float) maxBounds.getWidth() + 1;
Shape shape = at.createTransformedShape(shapes[i]);
Rectangle2D b1 = shape.getBounds2D();
if ((type & R) != 0) {
at.rotate(Math.toRadians(rotate));
}
if ((type & SC) != 0) {
at.scale(sx, sy);
}
shape = at.createTransformedShape(shapes[i]);
Rectangle2D b2 = shape.getBounds2D();
double xx = (b1.getX() + b1.getWidth() / 2)
- (b2.getX() + b2.getWidth() / 2);
double yy = (b1.getY() + b1.getHeight() / 2)
- (b2.getY() + b2.getHeight() / 2);
AffineTransform toCenterAT = new AffineTransform();
toCenterAT.translate(xx, yy);
toCenterAT.concatenate(at);
txShapes[i] = toCenterAT.createTransformedShape(shapes[i]);
}
// avoid over rotation
if (Math.abs(rotate) <= numRev * 360) {
rotate += rIncr;
if ((type & SCX) != 0) {
sx += sIncr;
} else if ((type & SCY) != 0) {
sy += sIncr;
} else {
sx += sIncr;
sy += sIncr;
}
}
}
@Override
public void render(int w, int h, Graphics2D g2) {
Composite saveAC = null;
if ((type & AC) != 0 && sx > 0 && sx < 1) {
saveAC = g2.getComposite();
g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, (float) sx));
}
GeneralPath path = null;
if ((type & CLIP) != 0) {
path = new GeneralPath();
}
if (paint != null) {
g2.setPaint(paint);
}
for (int i = 0; i < txShapes.length; i++) {
if ((type & CLIP) != 0) {
path.append(txShapes[i], false);
} else {
g2.fill(txShapes[i]);
}
}
if ((type & CLIP) != 0) {
g2.clip(path);
}
if (saveAC != null) {
g2.setComposite(saveAC);
}
}
@Override
public int getBegin() {
return beginning;
}
@Override
public int getEnd() {
return ending;
}
} // End TxE class
/**
* GradientPaint Effect. Burst, split, horizontal and
* vertical gradient fill effects.
*/
static class GpE implements Part {
static final int INC = 1; // increasing
static final int DEC = 2; // decreasing
static final int CNT = 4; // center
static final int WID = 8; // width
static final int WI = WID | INC;
static final int WD = WID | DEC;
static final int HEI = 16; // height
static final int HI = HEI | INC;
static final int HD = HEI | DEC;
static final int SPL = 32 | CNT; // split
static final int SIW = SPL | INC | WID;
static final int SDW = SPL | DEC | WID;
static final int SIH = SPL | INC | HEI;
static final int SDH = SPL | DEC | HEI;
static final int BUR = 64 | CNT; // burst
static final int BURI = BUR | INC;
static final int BURD = BUR | DEC;
static final int NF = 128; // no fill
private Color c1, c2;
private int beginning, ending;
private float incr, index;
private List<Rectangle2D> rect = new ArrayList<Rectangle2D>();
private List<GradientPaint> grad = new ArrayList<GradientPaint>();
private int type;
public GpE(int type, Color c1, Color c2, int beg, int end) {
this.type = type;
this.c1 = c1;
this.c2 = c2;
this.beginning = beg;
this.ending = end;
}
@Override
public void reset(int w, int h) {
incr = 1.0f / (ending - beginning);
if ((type & CNT) != 0) {
incr /= 2.3f;
}
if ((type & CNT) != 0 && (type & INC) != 0) {
index = 0.5f;
} else if ((type & DEC) != 0) {
index = 1.0f;
incr = -incr;
} else {
index = 0.0f;
}
index += incr;
}
@Override
public void step(int w, int h) {
rect.clear();
grad.clear();
if ((type & WID) != 0) {
float w2 = 0, x1 = 0, x2 = 0;
if ((type & SPL) != 0) {
w2 = w * 0.5f;
x1 = w * (1.0f - index);
x2 = w * index;
} else {
w2 = w * index;
x1 = x2 = w2;
}
rect.add(new Rectangle2D.Float(0, 0, w2, h));
rect.add(new Rectangle2D.Float(w2, 0, w - w2, h));
grad.add(new GradientPaint(0, 0, c1, x1, 0, c2));
grad.add(new GradientPaint(x2, 0, c2, w, 0, c1));
} else if ((type & HEI) != 0) {
float h2 = 0, y1 = 0, y2 = 0;
if ((type & SPL) != 0) {
h2 = h * 0.5f;
y1 = h * (1.0f - index);
y2 = h * index;
} else {
h2 = h * index;
y1 = y2 = h2;
}
rect.add(new Rectangle2D.Float(0, 0, w, h2));
rect.add(new Rectangle2D.Float(0, h2, w, h - h2));
grad.add(new GradientPaint(0, 0, c1, 0, y1, c2));
grad.add(new GradientPaint(0, y2, c2, 0, h, c1));
} else if ((type & BUR) != 0) {
float w2 = w / 2;
float h2 = h / 2;
rect.add(new Rectangle2D.Float(0, 0, w2, h2));
rect.add(new Rectangle2D.Float(w2, 0, w2, h2));
rect.add(new Rectangle2D.Float(0, h2, w2, h2));
rect.add(new Rectangle2D.Float(w2, h2, w2, h2));
float x1 = w * (1.0f - index);
float x2 = w * index;
float y1 = h * (1.0f - index);
float y2 = h * index;
grad.add(new GradientPaint(0, 0, c1, x1, y1, c2));
grad.add(new GradientPaint(w, 0, c1, x2, y1, c2));
grad.add(new GradientPaint(0, h, c1, x1, y2, c2));
grad.add(new GradientPaint(w, h, c1, x2, y2, c2));
} else if ((type & NF) != 0) {
float y = h * index;
grad.add(new GradientPaint(0, 0, c1, 0, y, c2));
}
if ((type & INC) != 0 || (type & DEC) != 0) {
index += incr;
}
}
@Override
public void render(int w, int h, Graphics2D g2) {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_OFF);
for (int i = 0; i < grad.size(); i++) {
g2.setPaint(grad.get(i));
if ((type & NF) == 0) {
g2.fill(rect.get(i));
}
}
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
@Override
public int getBegin() {
return beginning;
}
@Override
public int getEnd() {
return ending;
}
} // End GpE class
/**
* TexturePaint Effect. Expand and collapse a texture.
*/
static final class TpE implements Part {
static final int INC = 1; // increasing
static final int DEC = 2; // decreasing
static final int OVAL = 4; // oval
static final int RECT = 8; // rectangle
static final int HAF = 16; // half oval or rect size
static final int NF = 32; // no fill
static final int OI = OVAL | INC;
static final int OD = OVAL | DEC;
static final int RI = RECT | INC;
static final int RD = RECT | DEC;
private Paint p1, p2;
private int beginning, ending;
private float incr, index;
private TexturePaint texture;
private int type;
private int size;
private BufferedImage bimg;
private Rectangle rect;
public TpE(int type, Paint p1, Paint p2, int size,
int beg, int end) {
this.type = type;
this.p1 = p1;
this.p2 = p2;
this.beginning = beg;
this.ending = end;
setTextureSize(size);
}
public void setTextureSize(int size) {
this.size = size;
bimg = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
rect = new Rectangle(0, 0, size, size);
}
@Override
public void reset(int w, int h) {
incr = (float) (size) / (float) (ending - beginning);
if ((type & HAF) != 0) {
incr /= 2;
}
if ((type & DEC) != 0) {
index = size;
if ((type & HAF) != 0) {
index /= 2;
}
incr = -incr;
} else {
index = 0.0f;
}
index += incr;
}
@Override
public void step(int w, int h) {
Graphics2D g2 = bimg.createGraphics();
g2.setPaint(p1);
g2.fillRect(0, 0, size, size);
g2.setPaint(p2);
if ((type & OVAL) != 0) {
g2.fill(new Ellipse2D.Float(0, 0, index, index));
} else if ((type & RECT) != 0) {
g2.fill(new Rectangle2D.Float(0, 0, index, index));
}
texture = new TexturePaint(bimg, rect);
g2.dispose();
index += incr;
}
@Override
public void render(int w, int h, Graphics2D g2) {
g2.setPaint(texture);
if ((type & NF) == 0) {
g2.fillRect(0, 0, w, h);
}
}
@Override
public int getBegin() {
return beginning;
}
@Override
public int getEnd() {
return ending;
}
} // End TpE class
/**
* Close out effect. Close out the buffered image with different
* geometry shapes.
*/
static class CoE implements Part {
private final Surface surf;
static final int WID = 1;
static final int HEI = 2;
static final int OVAL = 4;
static final int RECT = 8;
static final int RAND = 16;
static final int ARC = 32;
private int type;
private int beginning, ending;
private BufferedImage bimg;
private Shape shape;
private double zoom, extent;
private double zIncr, eIncr;
private boolean doRandom;
public CoE(int type, int beg, int end, Surface surf) {
this.type = type;
this.beginning = beg;
this.ending = end;
this.surf = surf;
zIncr = -(2.0 / (ending - beginning));
eIncr = 360.0 / (ending - beginning);
doRandom = (type & RAND) != 0;
}
@Override
public void reset(int w, int h) {
if (doRandom) {
int num = (int) (Math.random() * 5.0);
switch (num) {
case 0:
type = OVAL;
break;
case 1:
type = RECT;
break;
case 2:
type = RECT | WID;
break;
case 3:
type = RECT | HEI;
break;
case 4:
type = ARC;
break;
default:
type = OVAL;
}
}
shape = null;
bimg = null;
extent = 360.0;
zoom = 2.0;
}
@Override
public void step(int w, int h) {
if (bimg == null) {
int biw = surf.bimg.getWidth();
int bih = surf.bimg.getHeight();
bimg = new BufferedImage(biw, bih,
BufferedImage.TYPE_INT_RGB);
Graphics2D big = bimg.createGraphics();
big.drawImage(surf.bimg, 0, 0, null);
}
double z = Math.min(w, h) * zoom;
if ((type & OVAL) != 0) {
shape = new Ellipse2D.Double(w / 2 - z / 2, h / 2 - z / 2, z,
z);
} else if ((type & ARC) != 0) {
shape = new Arc2D.Double(-100, -100, w + 200, h + 200, 90,
extent, Arc2D.PIE);
extent -= eIncr;
} else if ((type & RECT) != 0) {
if ((type & WID) != 0) {
shape = new Rectangle2D.Double(w / 2 - z / 2, 0, z, h);
} else if ((type & HEI) != 0) {
shape = new Rectangle2D.Double(0, h / 2 - z / 2, w, z);
} else {
shape = new Rectangle2D.Double(w / 2 - z / 2, h / 2 - z
/ 2, z, z);
}
}
zoom += zIncr;
}
@Override
public void render(int w, int h, Graphics2D g2) {
g2.clip(shape);
g2.drawImage(bimg, 0, 0, null);
}
@Override
public int getBegin() {
return beginning;
}
@Override
public int getEnd() {
return ending;
}
} // End CoE class
/**
* Dither Dissolve Effect. For each successive step in the animation,
* a pseudo-random starting horizontal position is chosen using list,
* and then the corresponding points created from xlist and ylist are
* blacked out for the current "chunk". The x and y chunk starting
* positions are each incremented by the associated chunk size, and
* this process is repeated for the number of "steps" in the
* animation, causing an equal number of pseudo-randomly picked
* "blocks" to be blacked out during each step of the animation.
*/
static class DdE implements Part {
private final Surface surf;
private int beginning, ending;
private BufferedImage bimg;
private Graphics2D big;
private List<Integer> list, xlist, ylist;
private int xeNum, yeNum; // element number
private int xcSize, ycSize; // chunk size
private int inc;
private int blocksize;
public DdE(int beg, int end, int blocksize, Surface surf) {
this.beginning = beg;
this.ending = end;
this.blocksize = blocksize;
this.surf = surf;
}
private void createShuffledLists() {
int width = bimg.getWidth();
int height = bimg.getHeight();
xlist = new ArrayList<Integer>(width);
ylist = new ArrayList<Integer>(height);
list = new ArrayList<Integer>(ending - beginning + 1);
for (int i = 0; i < width; i++) {
xlist.add(i, i);
}
for (int i = 0; i < height; i++) {
ylist.add(i, i);
}
for (int i = 0; i < (ending - beginning + 1); i++) {
list.add(i, i);
}
java.util.Collections.shuffle(xlist);
java.util.Collections.shuffle(ylist);
java.util.Collections.shuffle(list);
}
@Override
public void reset(int w, int h) {
bimg = null;
}
@Override
public void step(int w, int h) {
if (inc > ending) {
bimg = null;
}
if (bimg == null) {
int biw = surf.bimg.getWidth();
int bih = surf.bimg.getHeight();
bimg = new BufferedImage(biw, bih,
BufferedImage.TYPE_INT_RGB);
createShuffledLists();
big = bimg.createGraphics();
big.drawImage(surf.bimg, 0, 0, null);
xcSize = (xlist.size() / (ending - beginning)) + 1;
ycSize = (ylist.size() / (ending - beginning)) + 1;
xeNum = 0;
inc = 0;
}
xeNum = xcSize * (list.get(inc)).intValue();
yeNum = -ycSize;
inc++;
}
@Override
public void render(int w, int h, Graphics2D g2) {
big.setColor(myBlack);
for (int k = 0; k <= (ending - beginning); k++) {
if ((xeNum + xcSize) > xlist.size()) {
xeNum = 0;
} else {
xeNum += xcSize;
}
yeNum += ycSize;
for (int i = xeNum; i < xeNum + xcSize && i < xlist.size();
i++) {
for (int j = yeNum; j < yeNum + ycSize && j
< ylist.size(); j++) {
int xval = (xlist.get(i)).intValue();
int yval = (ylist.get(j)).intValue();
if (((xval % blocksize) == 0) && ((yval % blocksize)
== 0)) {
big.fillRect(xval, yval, blocksize, blocksize);
}
}
}
}
g2.drawImage(bimg, 0, 0, null);
}
@Override
public int getBegin() {
return beginning;
}
@Override
public int getEnd() {
return ending;
}
} // End DdE class
/**
* Subimage effect. Subimage the scene's buffered
* image then rotate and scale down the subimages.
*/
static class SiE implements Part {
private final Surface surf;
private int beginning, ending;
private BufferedImage bimg;
private double rIncr, sIncr;
private double scale, rotate;
private int siw, sih;
private List<BufferedImage> subs = new ArrayList<BufferedImage>(20);
private List<Point> pts = new ArrayList<Point>(20);
public SiE(int siw, int sih, int beg, int end, Surface surf) {
this.siw = siw;
this.sih = sih;
this.beginning = beg;
this.ending = end;
this.surf = surf;
rIncr = 360.0 / (ending - beginning);
sIncr = 1.0 / (ending - beginning);
}
@Override
public void reset(int w, int h) {
scale = 1.0;
rotate = 0.0;
bimg = null;
subs.clear();
pts.clear();
}
@Override
public void step(int w, int h) {
if (bimg == null) {
int biw = surf.bimg.getWidth();
int bih = surf.bimg.getHeight();
bimg = new BufferedImage(biw, bih,
BufferedImage.TYPE_INT_RGB);
Graphics2D big = bimg.createGraphics();
big.drawImage(surf.bimg, 0, 0, null);
for (int x = 0; x < w && scale > 0.0; x += siw) {
int ww = x + siw < w ? siw : w - x;
for (int y = 0; y < h; y += sih) {
int hh = y + sih < h ? sih : h - y;
subs.add(bimg.getSubimage(x, y, ww, hh));
pts.add(new Point(x, y));
}
}
}
rotate += rIncr;
scale -= sIncr;
}
@Override
public void render(int w, int h, Graphics2D g2) {
AffineTransform saveTx = g2.getTransform();
g2.setColor(myBlue);
for (int i = 0; i < subs.size() && scale > 0.0; i++) {
BufferedImage bi = subs.get(i);
Point p = pts.get(i);
int ww = bi.getWidth();
int hh = bi.getHeight();
AffineTransform at = new AffineTransform();
at.rotate(Math.toRadians(rotate), p.x + ww / 2, p.y + hh / 2);
at.translate(p.x, p.y);
at.scale(scale, scale);
Rectangle b1 = new Rectangle(0, 0, ww, hh);
Shape shape = at.createTransformedShape(b1);
Rectangle2D b2 = shape.getBounds2D();
double xx = (p.x + ww / 2) - (b2.getX() + b2.getWidth() / 2);
double yy = (p.y + hh / 2)
- (b2.getY() + b2.getHeight() / 2);
AffineTransform toCenterAT = new AffineTransform();
toCenterAT.translate(xx, yy);
toCenterAT.concatenate(at);
g2.setTransform(toCenterAT);
g2.drawImage(bi, 0, 0, null);
g2.draw(b1);
}
g2.setTransform(saveTx);
}
@Override
public int getBegin() {
return beginning;
}
@Override
public int getEnd() {
return ending;
}
} // End SiE class
/**
* Line Effect. Flattened ellipse with lines from the center
* to the edge. Expand or collapse the ellipse. Fade in or out
* the lines.
*/
static class LnE implements Part {
static final int INC = 1;
static final int DEC = 2;
static final int R = 4; // rotate
static final int ZOOM = 8; // zoom
static final int AC = 32; // AlphaComposite
static final int RI = R | INC;
static final int RD = R | DEC;
static final int ZOOMI = ZOOM | INC;
static final int ZOOMD = ZOOM | DEC;
static final int ACI = AC | INC;
static final int ACD = AC | DEC;
private int beginning, ending;
private double rIncr, rotate;
private double zIncr, zoom;
private List<Point2D.Double> pts = new ArrayList<Point2D.Double>();
private float alpha, aIncr;
private int type;
public LnE(int type, int beg, int end) {
this.type = type;
this.beginning = beg;
this.ending = end;
float range = ending - beginning;
rIncr = 360.0f / range;
aIncr = 0.9f / range;
zIncr = 2.0f / range;
if ((type & DEC) != 0) {
rIncr = -rIncr;
aIncr = -aIncr;
zIncr = -zIncr;
}
}
public void generatePts(int w, int h, double sizeF) {
pts.clear();
double size = Math.min(w, h) * sizeF;
Ellipse2D ellipse = new Ellipse2D.Double(w / 2 - size / 2, h / 2 - size
/ 2, size, size);
PathIterator pi = ellipse.getPathIterator(null, 0.8);
while (!pi.isDone()) {
double[] pt = new double[6];
switch (pi.currentSegment(pt)) {
case FlatteningPathIterator.SEG_MOVETO:
case FlatteningPathIterator.SEG_LINETO:
pts.add(new Point2D.Double(pt[0], pt[1]));
}
pi.next();
}
}
@Override
public void reset(int w, int h) {
if ((type & DEC) != 0) {
rotate = 360;
alpha = 1.0f;
zoom = 2.0;
} else {
rotate = alpha = 0;
zoom = 0;
}
if ((type & ZOOM) == 0) {
generatePts(w, h, 0.5);
}
}
@Override
public void step(int w, int h) {
if ((type & ZOOM) != 0) {
generatePts(w, h, zoom += zIncr);
}
if ((type & RI) != 0 || (type & RI) != 0) {
rotate += rIncr;
}
if ((type & ACI) != 0 || (type & ACD) != 0) {
alpha += aIncr;
}
}
@Override
public void render(int w, int h, Graphics2D g2) {
Composite saveAC = null;
if ((type & AC) != 0 && alpha >= 0 && alpha <= 1) {
saveAC = g2.getComposite();
g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, alpha));
}
AffineTransform saveTx = null;
if ((type & R) != 0) {
saveTx = g2.getTransform();
AffineTransform at = new AffineTransform();
at.rotate(Math.toRadians(rotate), w / 2, h / 2);
g2.setTransform(at);
}
Point2D p1 = new Point2D.Double(w / 2, h / 2);
g2.setColor(YELLOW);
for (Point2D pt : pts) {
g2.draw(new Line2D.Float(p1, pt));
}
if (saveTx != null) {
g2.setTransform(saveTx);
}
if (saveAC != null) {
g2.setComposite(saveAC);
}
}
@Override
public int getBegin() {
return beginning;
}
@Override
public int getEnd() {
return ending;
}
} // End LnE class
/**
* Template for Features & Contributors consisting of translating
* blue and red rectangles and an image going from transparent to
* opaque.
*/
static class Temp implements Part {
static final int NOANIM = 1;
static final int RECT = 2;
static final int IMG = 4;
static final int RNA = RECT | NOANIM;
static final int INA = IMG | NOANIM;
private int beginning, ending;
private float alpha, aIncr;
private int type;
private Rectangle rect1, rect2;
private int x, y, xIncr, yIncr;
private Image img;
public Temp(int type, Image img, int beg, int end) {
this.type = type;
this.img = img;
this.beginning = beg;
this.ending = end;
aIncr = 0.9f / (ending - beginning);
if ((type & NOANIM) != 0) {
alpha = 1.0f;
}
}
@Override
public void reset(int w, int h) {
rect1 = new Rectangle(8, 20, w - 20, 30);
rect2 = new Rectangle(20, 8, 30, h - 20);
if ((type & NOANIM) == 0) {
alpha = 0.0f;
xIncr = w / (ending - beginning);
yIncr = h / (ending - beginning);
x = w + (int) (xIncr * 1.4);
y = h + (int) (yIncr * 1.4);
}
}
@Override
public void step(int w, int h) {
if ((type & NOANIM) != 0) {
return;
}
if ((type & RECT) != 0) {
rect1.setLocation(x -= xIncr, 20);
rect2.setLocation(20, y -= yIncr);
}
if ((type & IMG) != 0) {
alpha += aIncr;
}
}
@Override
public void render(int w, int h, Graphics2D g2) {
if ((type & RECT) != 0) {
g2.setColor(myBlue);
g2.fill(rect1);
g2.setColor(myRed);
g2.fill(rect2);
}
if ((type & IMG) != 0) {
Composite saveAC = g2.getComposite();
if (alpha >= 0 && alpha <= 1) {
g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, alpha));
}
g2.drawImage(img, 30, 30, null);
g2.setComposite(saveAC);
}
}
@Override
public int getBegin() {
return beginning;
}
@Override
public int getEnd() {
return ending;
}
} // End Temp class
/**
* Features of Java2D(TM). Single character advancement effect.
*/
static class Features implements Part {
static final int GRAPHICS = 0;
static final int TEXT = 1;
static final int IMAGES = 2;
static final int COLOR = 3;
static final Font font1 = new Font(Font.SERIF, Font.BOLD, 38);
static final Font font2 = new Font(Font.SERIF, Font.PLAIN, 24);
private final FontMetrics fm1;
private final FontMetrics fm2;
private static final String table[][] = { { "Graphics", "Antialiased rendering",
"Bezier paths",
"Transforms", "Compositing", "Stroking parameters" },
{ "Text", "Extended font support",
"Advanced text layout", "Dynamic font loading",
"AttributeSets for font customization" },
{ "Images", "Flexible image layouts",
"Extended imaging operations",
" Convolutions, Lookup Tables",
"RenderableImage interface" },
{ "Color", "ICC profile support", "Color conversion",
"Arbitrary color spaces" } };
private String list[];
private int beginning, ending;
private int strH;
private int endIndex, listIndex;
private List<String> v = new ArrayList<String>();
public Features(int type, int beg, int end, Surface surf) {
list = table[type];
this.beginning = beg;
this.ending = end;
fm1 = surf.getMetrics(font1);
fm2 = surf.getMetrics(font2);
}
@Override
public void reset(int w, int h) {
strH = (fm2.getAscent() + fm2.getDescent());
endIndex = 1;
listIndex = 0;
v.clear();
v.add(list[listIndex].substring(0, endIndex));
}
@Override
public void step(int w, int h) {
if (listIndex < list.length) {
if (++endIndex > list[listIndex].length()) {
if (++listIndex < list.length) {
endIndex = 1;
v.add(list[listIndex].substring(0, endIndex));
}
} else {
v.set(listIndex, list[listIndex].substring(0, endIndex));
}
}
}
@Override
public void render(int w, int h, Graphics2D g2) {
g2.setColor(myWhite);
g2.setFont(font1);
g2.drawString(v.get(0), 90, 85);
g2.setFont(font2);
for (int i = 1, y = 90; i < v.size(); i++) {
g2.drawString(v.get(i), 120, y += strH);
}
}
@Override
public int getBegin() {
return beginning;
}
@Override
public int getEnd() {
return ending;
}
} // End Features class
/**
* Scrolling text of Java2D(TM) contributors.
*/
static class Contributors implements Part {
private static final String members[] = {
"Brian Lichtenwalter", "Jeannette Hung",
"Thanh Nguyen", "Jim Graham", "Jerry Evans",
"John Raley", "Michael Peirce", "Robert Kim",
"Jennifer Ball", "Deborah Adair", "Paul Charlton",
"Dmitry Feld", "Gregory Stone", "Richard Blanchard",
"Link Perry", "Phil Race", "Vincent Hardy",
"Parry Kejriwal", "Doug Felt", "Rekha Rangarajan",
"Paula Patel", "Michael Bundschuh", "Joe Warzecha",
"Joey Beheler", "Aastha Bhardwaj", "Daniel Rice",
"Chris Campbell", "Shinsuke Fukuda", "Dmitri Trembovetski",
"Chet Haase", "Jennifer Godinez", "Nicholas Talian",
"Raul Vera", "Ankit Patel", "Ilya Bagrak",
"Praveen Mohan", "Rakesh Menon"
};
private static final Font font = new Font(Font.SERIF, Font.PLAIN, 26);
private final FontMetrics fm;
private int beginning, ending;
private int nStrs, strH, index, yh, height;
private List<String> v = new ArrayList<String>();
private List<String> cast =
new ArrayList<String>(members.length + 3);
private int counter, cntMod;
private GradientPaint gp;
public Contributors(int beg, int end, Surface surf) {
this.beginning = beg;
this.ending = end;
fm = surf.getMetrics(font);
java.util.Arrays.sort(members);
cast.add("CONTRIBUTORS");
cast.add(" ");
cast.addAll(Arrays.asList(members));
cast.add(" ");
cast.add(" ");
cntMod = (ending - beginning) / cast.size() - 1;
}
@Override
public void reset(int w, int h) {
v.clear();
strH = (fm.getAscent() + fm.getDescent());
nStrs = (h - 40) / strH + 1;
height = strH * (nStrs - 1) + 48;
index = 0;
gp = new GradientPaint(0, h / 2, WHITE, 0, h + 20, BLACK);
counter = 0;
}
@Override
public void step(int w, int h) {
if (counter++ % cntMod == 0) {
if (index < cast.size()) {
v.add(cast.get(index));
}
if ((v.size() == nStrs || index >= cast.size()) && !v.
isEmpty()) {
v.remove(0);
}
++index;
}
}
@Override
public void render(int w, int h, Graphics2D g2) {
g2.setPaint(gp);
g2.setFont(font);
double remainder = counter % cntMod;
double incr = 1.0 - remainder / cntMod;
incr = incr == 1.0 ? 0 : incr;
int y = (int) (incr * strH);
if (index >= cast.size()) {
y = yh + y;
} else {
y = yh = height - v.size() * strH + y;
}
for (String s : v) {
g2.drawString(s, w / 2 - fm.stringWidth(s) / 2, y += strH);
}
}
@Override
public int getBegin() {
return beginning;
}
@Override
public int getEnd() {
return ending;
}
} // End Contributors class
} // End Surface class
} // End Intro class