1 /* 2 * 3 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * - Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * - Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * - Neither the name of Oracle nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package java2d; 33 34 35 import static java.awt.Color.BLACK; 36 import static java.awt.Color.GRAY; 37 import static java.awt.Color.RED; 38 import static java.awt.Color.WHITE; 39 import static java.awt.Color.YELLOW; 40 import java.awt.AlphaComposite; 41 import java.awt.BorderLayout; 42 import java.awt.Color; 43 import java.awt.Composite; 44 import java.awt.Dimension; 45 import java.awt.Font; 46 import java.awt.FontMetrics; 47 import java.awt.GradientPaint; 48 import java.awt.Graphics; 49 import java.awt.Graphics2D; 50 import java.awt.Image; 51 import java.awt.Paint; 52 import java.awt.Point; 53 import java.awt.Rectangle; 54 import java.awt.RenderingHints; 55 import java.awt.Shape; 56 import java.awt.TexturePaint; 57 import java.awt.Toolkit; 58 import java.awt.event.ActionEvent; 59 import java.awt.event.ActionListener; 60 import java.awt.event.MouseAdapter; 61 import java.awt.event.MouseEvent; 62 import java.awt.event.WindowAdapter; 63 import java.awt.event.WindowEvent; 64 import java.awt.event.WindowListener; 65 import java.awt.font.FontRenderContext; 66 import java.awt.font.TextLayout; 67 import java.awt.geom.AffineTransform; 68 import java.awt.geom.Arc2D; 69 import java.awt.geom.Ellipse2D; 70 import java.awt.geom.FlatteningPathIterator; 71 import java.awt.geom.GeneralPath; 72 import java.awt.geom.Line2D; 73 import java.awt.geom.PathIterator; 74 import java.awt.geom.Point2D; 75 import java.awt.geom.Rectangle2D; 76 import java.awt.image.BufferedImage; 77 import java.util.ArrayList; 78 import java.util.Arrays; 79 import java.util.List; 80 import javax.swing.JButton; 81 import javax.swing.JFrame; 82 import javax.swing.JPanel; 83 import javax.swing.JScrollPane; 84 import javax.swing.JSlider; 85 import javax.swing.JTable; 86 import javax.swing.border.BevelBorder; 87 import javax.swing.border.CompoundBorder; 88 import javax.swing.border.EmptyBorder; 89 import javax.swing.border.EtchedBorder; 90 import javax.swing.border.TitledBorder; 91 import javax.swing.event.ChangeEvent; 92 import javax.swing.event.ChangeListener; 93 import javax.swing.event.TableModelEvent; 94 import javax.swing.table.AbstractTableModel; 95 import javax.swing.table.TableColumn; 96 import javax.swing.table.TableModel; 97 98 99 /** 100 * Introduction to the J2Ddemo. 101 * 102 * @author Brian Lichtenwalter 103 * @author Alexander Kouznetsov 104 */ 105 @SuppressWarnings("serial") 106 public class Intro extends JPanel { 107 108 private static final Color myBlack = new Color(20, 20, 20); 109 private static final Color myWhite = new Color(240, 240, 255); 110 private static final Color myRed = new Color(149, 43, 42); 111 private static final Color myBlue = new Color(94, 105, 176); 112 private static final Color myYellow = new Color(255, 255, 140); 113 private ScenesTable scenesTable; 114 private boolean doTable; 115 private final Surface surface; 116 117 public Intro() { 118 EmptyBorder eb = new EmptyBorder(80, 110, 80, 110); 119 BevelBorder bb = new BevelBorder(BevelBorder.LOWERED); 120 setBorder(new CompoundBorder(eb, bb)); 121 setLayout(new BorderLayout()); 122 setBackground(GRAY); 123 setToolTipText("click for scene table"); 124 add(surface = new Surface()); 125 addMouseListener(new MouseAdapter() { 126 127 @Override 128 public void mouseClicked(MouseEvent e) { 129 removeAll(); 130 if ((doTable = !doTable)) { 131 setToolTipText("click for animation"); 132 surface.stop(); 133 if (scenesTable == null) { 134 scenesTable = new ScenesTable(Intro.this); 135 } 136 add(scenesTable); 137 } else { 138 setToolTipText("click for scene table"); 139 surface.start(); 140 add(surface); 141 } 142 revalidate(); 143 repaint(); 144 } 145 }); 146 } 147 148 public void start() { 149 if (!doTable) { 150 surface.start(); 151 } 152 } 153 154 public void stop() { 155 if (!doTable) { 156 surface.stop(); 157 } 158 } 159 160 public static void main(String argv[]) { 161 final Intro intro = new Intro(); 162 WindowListener l = new WindowAdapter() { 163 164 @Override 165 public void windowClosing(WindowEvent e) { 166 System.exit(0); 167 } 168 169 @Override 170 public void windowDeiconified(WindowEvent e) { 171 intro.start(); 172 } 173 174 @Override 175 public void windowIconified(WindowEvent e) { 176 intro.stop(); 177 } 178 }; 179 JFrame f = new JFrame("Java2D(TM) Demo - Intro"); 180 f.addWindowListener(l); 181 f.getContentPane().add("Center", intro); 182 f.pack(); 183 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 184 int w = 720; 185 int h = 510; 186 f.setLocation(screenSize.width / 2 - w / 2, screenSize.height / 2 - h 187 / 2); 188 f.setSize(w, h); 189 f.setVisible(true); 190 intro.start(); 191 } 192 193 194 /** 195 * ScenesTable is the list of scenes known to the Director. 196 * Scene participation, scene name and scene pause amount columns. 197 * Global animation delay for scene's steps. 198 */ 199 static class ScenesTable extends JPanel implements ActionListener, 200 ChangeListener { 201 private final Intro intro; 202 private JTable table; 203 private TableModel dataModel; 204 205 @SuppressWarnings("LeakingThisInConstructor") 206 public ScenesTable(final Intro intro) { 207 this.intro = intro; 208 209 setBackground(WHITE); 210 setLayout(new BorderLayout()); 211 final String[] names = { "", "Scenes", "Pause" }; 212 213 dataModel = new AbstractTableModel() { 214 215 @Override 216 public int getColumnCount() { 217 return names.length; 218 } 219 220 @Override 221 public int getRowCount() { 222 return intro.surface.director.size(); 223 } 224 225 @Override 226 public Object getValueAt(int row, int col) { 227 Surface.Scene scene = intro.surface.director.get(row); 228 if (col == 0) { 229 return scene.participate; 230 } else if (col == 1) { 231 return scene.name; 232 } else { 233 return scene.pauseAmt; 234 } 235 } 236 237 @Override 238 public String getColumnName(int col) { 239 return names[col]; 240 } 241 242 @Override 243 public Class<?> getColumnClass(int c) { 244 return getValueAt(0, c).getClass(); 245 } 246 247 @Override 248 public boolean isCellEditable(int row, int col) { 249 return col != 1 ? true : false; 250 } 251 252 @Override 253 public void setValueAt(Object aValue, int row, int col) { 254 Surface.Scene scene = intro.surface.director.get(row); 255 if (col == 0) { 256 scene.participate = aValue; 257 } else if (col == 1) { 258 scene.name = aValue; 259 } else { 260 scene.pauseAmt = aValue; 261 } 262 } 263 }; 264 265 table = new JTable(dataModel); 266 TableColumn col = table.getColumn(""); 267 col.setWidth(16); 268 col.setMinWidth(16); 269 col.setMaxWidth(20); 270 col = table.getColumn("Pause"); 271 col.setWidth(60); 272 col.setMinWidth(60); 273 col.setMaxWidth(60); 274 table.sizeColumnsToFit(0); 275 276 JScrollPane scrollpane = new JScrollPane(table); 277 add(scrollpane); 278 279 JPanel panel = new JPanel(new BorderLayout()); 280 JButton b = new JButton("Unselect All"); 281 b.setHorizontalAlignment(JButton.LEFT); 282 Font font = new Font(Font.SERIF, Font.PLAIN, 10); 283 b.setFont(font); 284 b.addActionListener(this); 285 panel.add("West", b); 286 287 JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 200, 288 (int) intro.surface.sleepAmt); 289 slider.addChangeListener(this); 290 TitledBorder tb = new TitledBorder(new EtchedBorder()); 291 tb.setTitleFont(font); 292 tb.setTitle("Anim delay = " + String.valueOf(intro.surface.sleepAmt) 293 + " ms"); 294 slider.setBorder(tb); 295 slider.setPreferredSize(new Dimension(140, 40)); 296 slider.setMinimumSize(new Dimension(100, 40)); 297 slider.setMaximumSize(new Dimension(180, 40)); 298 panel.add("East", slider); 299 300 add("South", panel); 301 } 302 303 @Override 304 public void actionPerformed(ActionEvent e) { 305 JButton b = (JButton) e.getSource(); 306 b.setSelected(!b.isSelected()); 307 b.setText(b.isSelected() ? "Select All" : "Unselect All"); 308 for (int i = 0; i < intro.surface.director.size(); i++) { 309 Surface.Scene scene = intro.surface.director.get(i); 310 scene.participate = Boolean.valueOf(!b.isSelected()); 311 } 312 table.tableChanged(new TableModelEvent(dataModel)); 313 } 314 315 @Override 316 public void stateChanged(ChangeEvent e) { 317 JSlider slider = (JSlider) e.getSource(); 318 int value = slider.getValue(); 319 TitledBorder tb = (TitledBorder) slider.getBorder(); 320 tb.setTitle("Anim delay = " + String.valueOf(value) + " ms"); 321 intro.surface.sleepAmt = (long) value; 322 slider.repaint(); 323 } 324 } // End ScenesTable class 325 326 327 /** 328 * Surface is the stage where the Director plays its scenes. 329 */ 330 static class Surface extends JPanel implements Runnable { 331 332 private final Image dukeanim, duke; 333 private BufferedImage bimg; 334 public Director director; 335 public int index; 336 public long sleepAmt = 30; 337 private Thread thread; 338 339 @SuppressWarnings("LeakingThisInConstructor") 340 public Surface() { 341 setBackground(myBlack); 342 setLayout(new BorderLayout()); 343 addMouseListener(new MouseAdapter() { 344 345 @Override 346 public void mouseClicked(MouseEvent e) { 347 if (thread == null) { 348 start(); 349 } else { 350 stop(); 351 } 352 } 353 }); 354 dukeanim = DemoImages.getImage("duke.running.gif", this); 355 duke = DemoImages.getImage("duke.png", this); 356 director = new Director(this); 357 } 358 359 public FontMetrics getMetrics(Font font) { 360 return getFontMetrics(font); 361 } 362 363 @Override 364 public void paint(Graphics g) { 365 Dimension d = getSize(); 366 if (d.width <= 0 || d.height <= 0) { 367 return; 368 } 369 if (bimg == null || bimg.getWidth() != d.width || bimg.getHeight() 370 != d.height) { 371 bimg = getGraphicsConfiguration().createCompatibleImage(d.width, 372 d.height); 373 // reset future scenes 374 for (int i = index + 1; i < director.size(); i++) { 375 (director.get(i)).reset(d.width, d.height); 376 } 377 } 378 379 Scene scene = director.get(index); 380 if (scene.index <= scene.length) { 381 if (thread != null) { 382 scene.step(d.width, d.height); 383 } 384 385 Graphics2D g2 = bimg.createGraphics(); 386 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 387 RenderingHints.VALUE_ANTIALIAS_ON); 388 g2.setBackground(getBackground()); 389 g2.clearRect(0, 0, d.width, d.height); 390 391 scene.render(d.width, d.height, g2); 392 393 if (thread != null) { 394 // increment scene.index after scene.render 395 scene.index++; 396 } 397 g2.dispose(); 398 } 399 g.drawImage(bimg, 0, 0, this); 400 } 401 402 public void start() { 403 if (thread == null) { 404 thread = new Thread(this); 405 thread.setPriority(Thread.MIN_PRIORITY); 406 thread.setName("Intro"); 407 thread.start(); 408 } 409 } 410 411 public synchronized void stop() { 412 if (thread != null) { 413 thread.interrupt(); 414 } 415 thread = null; 416 notifyAll(); 417 } 418 419 public void reset() { 420 index = 0; 421 Dimension d = getSize(); 422 for (Scene scene : director) { 423 scene.reset(d.width, d.height); 424 } 425 } 426 427 @Override 428 @SuppressWarnings("SleepWhileHoldingLock") 429 public void run() { 430 431 Thread me = Thread.currentThread(); 432 433 while (thread == me && !isShowing() || getSize().width <= 0) { 434 try { 435 Thread.sleep(500); 436 } catch (InterruptedException e) { 437 return; 438 } 439 } 440 441 if (index == 0) { 442 reset(); 443 } 444 445 while (thread == me) { 446 Scene scene = director.get(index); 447 if (((Boolean) scene.participate).booleanValue()) { 448 repaint(); 449 try { 450 Thread.sleep(sleepAmt); 451 } catch (InterruptedException e) { 452 break; 453 } 454 if (scene.index > scene.length) { 455 scene.pause(); 456 if (++index >= director.size()) { 457 reset(); 458 } 459 } 460 } else { 461 if (++index >= director.size()) { 462 reset(); 463 } 464 } 465 } 466 thread = null; 467 } 468 469 470 /** 471 * Part is a piece of the scene. Classes must implement Part 472 * in order to participate in a scene. 473 */ 474 interface Part { 475 476 public void reset(int newwidth, int newheight); 477 478 public void step(int w, int h); 479 480 public void render(int w, int h, Graphics2D g2); 481 482 public int getBegin(); 483 484 public int getEnd(); 485 } 486 487 488 /** 489 * Director is the holder of the scenes, their names & pause amounts 490 * between scenes. 491 */ 492 static class Director extends ArrayList<Scene> { 493 494 GradientPaint gp = new GradientPaint(0, 40, myBlue, 38, 2, myBlack); 495 Font f1 = new Font(Font.SERIF, Font.PLAIN, 200); 496 Font f2 = new Font(Font.SERIF, Font.PLAIN, 120); 497 Font f3 = new Font(Font.SERIF, Font.PLAIN, 72); 498 499 public Director(Surface surf) { 500 Object partsInfo[][][] = { 501 { { "J - scale text on gradient", "0" }, 502 { new GpE(GpE.BURI, myBlack, myBlue, 0, 20), 503 new TxE("J", f1, TxE.SCI, myYellow, 2, 20) } }, 504 { { "2 - scale & rotate text on gradient", "0" }, 505 { new GpE(GpE.BURI, myBlue, myBlack, 0, 22), 506 new TxE("2", f1, TxE.RI | TxE.SCI, myYellow, 2, 22) } }, 507 { { "D - scale text on gradient", "0" }, 508 { new GpE(GpE.BURI, myBlack, myBlue, 0, 20), 509 new TxE("D", f1, TxE.SCI, myYellow, 2, 20) } }, 510 { { "J2D demo - scale & rotate text on gradient", "1000" }, 511 { new GpE(GpE.SIH, myBlue, myBlack, 0, 40), 512 new TxE("J2D demo", f2, TxE.RI | TxE.SCI, myYellow, 0, 40) } }, 513 { { "Previous scene dither dissolve out", "0" }, 514 { new DdE(0, 20, 1, surf) } }, 515 { { "Graphics Features", "999" }, 516 { new Temp(Temp.RECT, null, 0, 15), 517 new Temp(Temp.IMG, surf.duke, 2, 15), 518 new Temp(Temp.RNA | Temp.INA, surf.duke, 16, 130), 519 new Features(Features.GRAPHICS, 16, 130, surf) } }, 520 { { "J2D demo - texture text on gradient", "1000" }, 521 { new GpE(GpE.WI, myBlue, myBlack, 0, 20), 522 new GpE(GpE.WD, myBlue, myBlack, 21, 40), 523 new TpE(TpE.OI | TpE.NF, myBlack, myYellow, 4, 0, 10), 524 new TpE(TpE.OD | TpE.NF, myBlack, myYellow, 4, 11, 20), 525 new TpE(TpE.OI | TpE.NF | TpE.HAF, myBlack, myYellow, 5, 526 21, 40), 527 new TxE("J2D demo", f2, 0, null, 0, 40) } }, 528 { { "Previous scene random close out", "0" }, 529 { new CoE(CoE.RAND, 0, 20, surf) } }, 530 { { "Text Features", "999" }, 531 { new Temp(Temp.RECT, null, 0, 15), 532 new Temp(Temp.IMG, surf.duke, 2, 15), 533 new Temp(Temp.RNA | Temp.INA, surf.duke, 16, 130), 534 new Features(Features.TEXT, 16, 130, surf) } }, 535 { { "J2D demo - composite text on texture", "1000" }, 536 { new TpE(TpE.RI, myBlack, gp, 40, 0, 20), 537 new TpE(TpE.RD, myBlack, gp, 40, 21, 40), 538 new TpE(TpE.RI, myBlack, gp, 40, 41, 60), 539 new TxE("J2D demo", f2, TxE.AC, myYellow, 0, 60) } }, 540 { { "Previous scene dither dissolve out", "0" }, 541 { new DdE(0, 20, 4, surf) } }, 542 { { "Imaging Features", "999" }, 543 { new Temp(Temp.RECT, null, 0, 15), 544 new Temp(Temp.IMG, surf.duke, 2, 15), 545 new Temp(Temp.RNA | Temp.INA, surf.duke, 16, 130), 546 new Features(Features.IMAGES, 16, 130, surf) } }, 547 { { "J2D demo - text on gradient", "1000" }, 548 { new GpE(GpE.SDH, myBlue, myBlack, 0, 20), 549 new GpE(GpE.SIH, myBlue, myBlack, 21, 40), 550 new GpE(GpE.SDH, myBlue, myBlack, 41, 50), 551 new GpE(GpE.INC | GpE.NF, myRed, myYellow, 0, 50), 552 new TxE("J2D demo", f2, TxE.NOP, null, 0, 50) } }, 553 { { "Previous scene ellipse close out", "0" }, 554 { new CoE(CoE.OVAL, 0, 20, surf) } }, 555 { { "Color Features", "999" }, 556 { new Temp(Temp.RECT, null, 0, 15), 557 new Temp(Temp.IMG, surf.duke, 2, 15), 558 new Temp(Temp.RNA | Temp.INA, surf.duke, 16, 99), 559 new Features(Features.COLOR, 16, 99, surf) } }, 560 { { "J2D demo - composite and rotate text on paints", "2000" }, 561 { new GpE(GpE.BURI, myBlack, myBlue, 0, 20), 562 new GpE(GpE.BURD, myBlack, myBlue, 21, 30), 563 new TpE(TpE.OI | TpE.HAF, myBlack, myBlue, 10, 31, 40), 564 new TxE("J2D demo", f2, TxE.AC | TxE.RI, myYellow, 0, 40) } }, 565 { { "Previous scene subimage transform out", "0" }, 566 { new SiE(60, 60, 0, 40, surf) } }, 567 { { "CREDITS - transform in", "1000" }, 568 { new LnE(LnE.ACI | LnE.ZOOMI | LnE.RI, 0, 60), 569 new TxE("CREDITS", f3, TxE.AC | TxE.SCI, RED, 20, 30), 570 new TxE("CREDITS", f3, TxE.SCXD, RED, 31, 38), 571 new TxE("CREDITS", f3, TxE.SCXI, RED, 39, 48), 572 new TxE("CREDITS", f3, TxE.SCXD, RED, 49, 54), 573 new TxE("CREDITS", f3, TxE.SCXI, RED, 55, 60) } }, 574 { { "CREDITS - transform out", "0" }, 575 { new LnE(LnE.ACD | LnE.ZOOMD | LnE.RD, 0, 45), 576 new TxE("CREDITS", f3, 0, RED, 0, 9), 577 new TxE("CREDITS", f3, TxE.SCD | TxE.RD, RED, 10, 30) } }, 578 { { "Contributors", "1000" }, 579 { new Temp(Temp.RECT, null, 0, 30), 580 new Temp(Temp.IMG, surf.dukeanim, 4, 30), 581 new Temp(Temp.RNA | Temp.INA, surf.dukeanim, 31, 200), 582 new Contributors(34, 200, surf) } }, }; 583 584 for (Object[][] partInfo : partsInfo) { 585 List<Part> parts = new ArrayList<Part>(); 586 for (Object part : partInfo[1]) { 587 parts.add((Part) part); 588 } 589 add(new Scene(parts, partInfo[0][0], partInfo[0][1])); 590 } 591 } 592 } 593 594 595 /** 596 * Scene is the manager of the parts. 597 */ 598 static class Scene extends Object { 599 600 public Object name; 601 public Object participate = Boolean.TRUE; 602 public Object pauseAmt; 603 public List<Part> parts; 604 public int index; 605 public int length; 606 607 public Scene(List<Part> parts, Object name, Object pauseAmt) { 608 this.name = name; 609 this.parts = parts; 610 this.pauseAmt = pauseAmt; 611 for (Part part : parts) { 612 int partLength = part.getEnd(); 613 if (partLength > length) { 614 length = partLength; 615 } 616 } 617 } 618 619 public void reset(int w, int h) { 620 index = 0; 621 for (int i = 0; i < parts.size(); i++) { 622 (parts.get(i)).reset(w, h); 623 } 624 } 625 626 public void step(int w, int h) { 627 for (int i = 0; i < parts.size(); i++) { 628 Part part = parts.get(i); 629 if (index >= part.getBegin() && index <= part.getEnd()) { 630 part.step(w, h); 631 } 632 } 633 } 634 635 public void render(int w, int h, Graphics2D g2) { 636 for (int i = 0; i < parts.size(); i++) { 637 Part part = parts.get(i); 638 if (index >= part.getBegin() && index <= part.getEnd()) { 639 part.render(w, h, g2); 640 } 641 } 642 } 643 644 public void pause() { 645 try { 646 Thread.sleep(Long.parseLong((String) pauseAmt)); 647 } catch (Exception ignored) { 648 } 649 System.gc(); 650 } 651 } // End Scene class 652 653 654 /** 655 * Text Effect. Transformation of characters. Clip or fill. 656 */ 657 static final class TxE implements Part { 658 659 static final int INC = 1; 660 static final int DEC = 2; 661 static final int R = 4; // rotate 662 static final int RI = R | INC; 663 static final int RD = R | DEC; 664 static final int SC = 8; // scale 665 static final int SCI = SC | INC; 666 static final int SCD = SC | DEC; 667 static final int SCX = 16; // scale invert x 668 static final int SCXI = SCX | SC | INC; 669 static final int SCXD = SCX | SC | DEC; 670 static final int SCY = 32; // scale invert y 671 static final int SCYI = SCY | SC | INC; 672 static final int SCYD = SCY | SC | DEC; 673 static final int AC = 64; // AlphaComposite 674 static final int CLIP = 128; // Clipping 675 static final int NOP = 512; // No Paint 676 private int beginning, ending; 677 private int type; 678 private double rIncr, sIncr; 679 private double sx, sy, rotate; 680 private Shape shapes[], txShapes[]; 681 private int sw; 682 private int numRev; 683 private Paint paint; 684 685 public TxE(String text, 686 Font font, 687 int type, 688 Paint paint, 689 int beg, 690 int end) { 691 this.type = type; 692 this.paint = paint; 693 this.beginning = beg; 694 this.ending = end; 695 696 setIncrements(2); 697 698 char[] chars = text.toCharArray(); 699 shapes = new Shape[chars.length]; 700 txShapes = new Shape[chars.length]; 701 FontRenderContext frc = new FontRenderContext(null, true, true); 702 TextLayout tl = new TextLayout(text, font, frc); 703 sw = (int) tl.getOutline(null).getBounds().getWidth(); 704 for (int j = 0; j < chars.length; j++) { 705 String s = String.valueOf(chars[j]); 706 shapes[j] = new TextLayout(s, font, frc).getOutline(null); 707 } 708 } 709 710 public void setIncrements(double numRevolutions) { 711 this.numRev = (int) numRevolutions; 712 rIncr = 360.0 / ((ending - beginning) / numRevolutions); 713 sIncr = 1.0 / (ending - beginning); 714 if ((type & SCX) != 0 || (type & SCY) != 0) { 715 sIncr *= 2; 716 } 717 if ((type & DEC) != 0) { 718 rIncr = -rIncr; 719 sIncr = -sIncr; 720 } 721 } 722 723 @Override 724 public void reset(int w, int h) { 725 if (type == SCXI) { 726 sx = -1.0; 727 sy = 1.0; 728 } else if (type == SCYI) { 729 sx = 1.0; 730 sy = -1.0; 731 } else { 732 sx = sy = (type & DEC) != 0 ? 1.0 : 0.0; 733 } 734 rotate = 0; 735 } 736 737 @Override 738 public void step(int w, int h) { 739 740 float charWidth = w / 2 - sw / 2; 741 742 for (int i = 0; i < shapes.length; i++) { 743 AffineTransform at = new AffineTransform(); 744 Rectangle2D maxBounds = shapes[i].getBounds(); 745 at.translate(charWidth, h / 2 + maxBounds.getHeight() / 2); 746 charWidth += (float) maxBounds.getWidth() + 1; 747 Shape shape = at.createTransformedShape(shapes[i]); 748 Rectangle2D b1 = shape.getBounds2D(); 749 750 if ((type & R) != 0) { 751 at.rotate(Math.toRadians(rotate)); 752 } 753 if ((type & SC) != 0) { 754 at.scale(sx, sy); 755 } 756 shape = at.createTransformedShape(shapes[i]); 757 Rectangle2D b2 = shape.getBounds2D(); 758 759 double xx = (b1.getX() + b1.getWidth() / 2) 760 - (b2.getX() + b2.getWidth() / 2); 761 double yy = (b1.getY() + b1.getHeight() / 2) 762 - (b2.getY() + b2.getHeight() / 2); 763 AffineTransform toCenterAT = new AffineTransform(); 764 toCenterAT.translate(xx, yy); 765 toCenterAT.concatenate(at); 766 txShapes[i] = toCenterAT.createTransformedShape(shapes[i]); 767 } 768 // avoid over rotation 769 if (Math.abs(rotate) <= numRev * 360) { 770 rotate += rIncr; 771 if ((type & SCX) != 0) { 772 sx += sIncr; 773 } else if ((type & SCY) != 0) { 774 sy += sIncr; 775 } else { 776 sx += sIncr; 777 sy += sIncr; 778 } 779 } 780 } 781 782 @Override 783 public void render(int w, int h, Graphics2D g2) { 784 Composite saveAC = null; 785 if ((type & AC) != 0 && sx > 0 && sx < 1) { 786 saveAC = g2.getComposite(); 787 g2.setComposite(AlphaComposite.getInstance( 788 AlphaComposite.SRC_OVER, (float) sx)); 789 } 790 GeneralPath path = null; 791 if ((type & CLIP) != 0) { 792 path = new GeneralPath(); 793 } 794 if (paint != null) { 795 g2.setPaint(paint); 796 } 797 for (int i = 0; i < txShapes.length; i++) { 798 if ((type & CLIP) != 0) { 799 path.append(txShapes[i], false); 800 } else { 801 g2.fill(txShapes[i]); 802 } 803 } 804 if ((type & CLIP) != 0) { 805 g2.clip(path); 806 } 807 if (saveAC != null) { 808 g2.setComposite(saveAC); 809 } 810 } 811 812 @Override 813 public int getBegin() { 814 return beginning; 815 } 816 817 @Override 818 public int getEnd() { 819 return ending; 820 } 821 } // End TxE class 822 823 824 /** 825 * GradientPaint Effect. Burst, split, horizontal and 826 * vertical gradient fill effects. 827 */ 828 static class GpE implements Part { 829 830 static final int INC = 1; // increasing 831 static final int DEC = 2; // decreasing 832 static final int CNT = 4; // center 833 static final int WID = 8; // width 834 static final int WI = WID | INC; 835 static final int WD = WID | DEC; 836 static final int HEI = 16; // height 837 static final int HI = HEI | INC; 838 static final int HD = HEI | DEC; 839 static final int SPL = 32 | CNT; // split 840 static final int SIW = SPL | INC | WID; 841 static final int SDW = SPL | DEC | WID; 842 static final int SIH = SPL | INC | HEI; 843 static final int SDH = SPL | DEC | HEI; 844 static final int BUR = 64 | CNT; // burst 845 static final int BURI = BUR | INC; 846 static final int BURD = BUR | DEC; 847 static final int NF = 128; // no fill 848 private Color c1, c2; 849 private int beginning, ending; 850 private float incr, index; 851 private List<Rectangle2D> rect = new ArrayList<Rectangle2D>(); 852 private List<GradientPaint> grad = new ArrayList<GradientPaint>(); 853 private int type; 854 855 public GpE(int type, Color c1, Color c2, int beg, int end) { 856 this.type = type; 857 this.c1 = c1; 858 this.c2 = c2; 859 this.beginning = beg; 860 this.ending = end; 861 } 862 863 @Override 864 public void reset(int w, int h) { 865 incr = 1.0f / (ending - beginning); 866 if ((type & CNT) != 0) { 867 incr /= 2.3f; 868 } 869 if ((type & CNT) != 0 && (type & INC) != 0) { 870 index = 0.5f; 871 } else if ((type & DEC) != 0) { 872 index = 1.0f; 873 incr = -incr; 874 } else { 875 index = 0.0f; 876 } 877 index += incr; 878 } 879 880 @Override 881 public void step(int w, int h) { 882 rect.clear(); 883 grad.clear(); 884 885 if ((type & WID) != 0) { 886 float w2 = 0, x1 = 0, x2 = 0; 887 if ((type & SPL) != 0) { 888 w2 = w * 0.5f; 889 x1 = w * (1.0f - index); 890 x2 = w * index; 891 } else { 892 w2 = w * index; 893 x1 = x2 = w2; 894 } 895 rect.add(new Rectangle2D.Float(0, 0, w2, h)); 896 rect.add(new Rectangle2D.Float(w2, 0, w - w2, h)); 897 grad.add(new GradientPaint(0, 0, c1, x1, 0, c2)); 898 grad.add(new GradientPaint(x2, 0, c2, w, 0, c1)); 899 } else if ((type & HEI) != 0) { 900 float h2 = 0, y1 = 0, y2 = 0; 901 if ((type & SPL) != 0) { 902 h2 = h * 0.5f; 903 y1 = h * (1.0f - index); 904 y2 = h * index; 905 } else { 906 h2 = h * index; 907 y1 = y2 = h2; 908 } 909 rect.add(new Rectangle2D.Float(0, 0, w, h2)); 910 rect.add(new Rectangle2D.Float(0, h2, w, h - h2)); 911 grad.add(new GradientPaint(0, 0, c1, 0, y1, c2)); 912 grad.add(new GradientPaint(0, y2, c2, 0, h, c1)); 913 } else if ((type & BUR) != 0) { 914 915 float w2 = w / 2; 916 float h2 = h / 2; 917 918 rect.add(new Rectangle2D.Float(0, 0, w2, h2)); 919 rect.add(new Rectangle2D.Float(w2, 0, w2, h2)); 920 rect.add(new Rectangle2D.Float(0, h2, w2, h2)); 921 rect.add(new Rectangle2D.Float(w2, h2, w2, h2)); 922 923 float x1 = w * (1.0f - index); 924 float x2 = w * index; 925 float y1 = h * (1.0f - index); 926 float y2 = h * index; 927 928 grad.add(new GradientPaint(0, 0, c1, x1, y1, c2)); 929 grad.add(new GradientPaint(w, 0, c1, x2, y1, c2)); 930 grad.add(new GradientPaint(0, h, c1, x1, y2, c2)); 931 grad.add(new GradientPaint(w, h, c1, x2, y2, c2)); 932 } else if ((type & NF) != 0) { 933 float y = h * index; 934 grad.add(new GradientPaint(0, 0, c1, 0, y, c2)); 935 } 936 937 if ((type & INC) != 0 || (type & DEC) != 0) { 938 index += incr; 939 } 940 } 941 942 @Override 943 public void render(int w, int h, Graphics2D g2) { 944 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 945 RenderingHints.VALUE_ANTIALIAS_OFF); 946 for (int i = 0; i < grad.size(); i++) { 947 g2.setPaint(grad.get(i)); 948 if ((type & NF) == 0) { 949 g2.fill(rect.get(i)); 950 } 951 } 952 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 953 RenderingHints.VALUE_ANTIALIAS_ON); 954 } 955 956 @Override 957 public int getBegin() { 958 return beginning; 959 } 960 961 @Override 962 public int getEnd() { 963 return ending; 964 } 965 } // End GpE class 966 967 968 /** 969 * TexturePaint Effect. Expand and collapse a texture. 970 */ 971 static final class TpE implements Part { 972 973 static final int INC = 1; // increasing 974 static final int DEC = 2; // decreasing 975 static final int OVAL = 4; // oval 976 static final int RECT = 8; // rectangle 977 static final int HAF = 16; // half oval or rect size 978 static final int NF = 32; // no fill 979 static final int OI = OVAL | INC; 980 static final int OD = OVAL | DEC; 981 static final int RI = RECT | INC; 982 static final int RD = RECT | DEC; 983 private Paint p1, p2; 984 private int beginning, ending; 985 private float incr, index; 986 private TexturePaint texture; 987 private int type; 988 private int size; 989 private BufferedImage bimg; 990 private Rectangle rect; 991 992 public TpE(int type, Paint p1, Paint p2, int size, 993 int beg, int end) { 994 this.type = type; 995 this.p1 = p1; 996 this.p2 = p2; 997 this.beginning = beg; 998 this.ending = end; 999 setTextureSize(size); 1000 } 1001 1002 public void setTextureSize(int size) { 1003 this.size = size; 1004 bimg = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB); 1005 rect = new Rectangle(0, 0, size, size); 1006 } 1007 1008 @Override 1009 public void reset(int w, int h) { 1010 incr = (float) (size) / (float) (ending - beginning); 1011 if ((type & HAF) != 0) { 1012 incr /= 2; 1013 } 1014 if ((type & DEC) != 0) { 1015 index = size; 1016 if ((type & HAF) != 0) { 1017 index /= 2; 1018 } 1019 incr = -incr; 1020 } else { 1021 index = 0.0f; 1022 } 1023 index += incr; 1024 } 1025 1026 @Override 1027 public void step(int w, int h) { 1028 Graphics2D g2 = bimg.createGraphics(); 1029 g2.setPaint(p1); 1030 g2.fillRect(0, 0, size, size); 1031 g2.setPaint(p2); 1032 if ((type & OVAL) != 0) { 1033 g2.fill(new Ellipse2D.Float(0, 0, index, index)); 1034 } else if ((type & RECT) != 0) { 1035 g2.fill(new Rectangle2D.Float(0, 0, index, index)); 1036 } 1037 texture = new TexturePaint(bimg, rect); 1038 g2.dispose(); 1039 index += incr; 1040 } 1041 1042 @Override 1043 public void render(int w, int h, Graphics2D g2) { 1044 g2.setPaint(texture); 1045 if ((type & NF) == 0) { 1046 g2.fillRect(0, 0, w, h); 1047 } 1048 } 1049 1050 @Override 1051 public int getBegin() { 1052 return beginning; 1053 } 1054 1055 @Override 1056 public int getEnd() { 1057 return ending; 1058 } 1059 } // End TpE class 1060 1061 1062 /** 1063 * Close out effect. Close out the buffered image with different 1064 * geometry shapes. 1065 */ 1066 static class CoE implements Part { 1067 private final Surface surf; 1068 static final int WID = 1; 1069 static final int HEI = 2; 1070 static final int OVAL = 4; 1071 static final int RECT = 8; 1072 static final int RAND = 16; 1073 static final int ARC = 32; 1074 private int type; 1075 private int beginning, ending; 1076 private BufferedImage bimg; 1077 private Shape shape; 1078 private double zoom, extent; 1079 private double zIncr, eIncr; 1080 private boolean doRandom; 1081 1082 public CoE(int type, int beg, int end, Surface surf) { 1083 this.type = type; 1084 this.beginning = beg; 1085 this.ending = end; 1086 this.surf = surf; 1087 zIncr = -(2.0 / (ending - beginning)); 1088 eIncr = 360.0 / (ending - beginning); 1089 doRandom = (type & RAND) != 0; 1090 } 1091 1092 @Override 1093 public void reset(int w, int h) { 1094 if (doRandom) { 1095 int num = (int) (Math.random() * 5.0); 1096 switch (num) { 1097 case 0: 1098 type = OVAL; 1099 break; 1100 case 1: 1101 type = RECT; 1102 break; 1103 case 2: 1104 type = RECT | WID; 1105 break; 1106 case 3: 1107 type = RECT | HEI; 1108 break; 1109 case 4: 1110 type = ARC; 1111 break; 1112 default: 1113 type = OVAL; 1114 } 1115 } 1116 shape = null; 1117 bimg = null; 1118 extent = 360.0; 1119 zoom = 2.0; 1120 } 1121 1122 @Override 1123 public void step(int w, int h) { 1124 if (bimg == null) { 1125 int biw = surf.bimg.getWidth(); 1126 int bih = surf.bimg.getHeight(); 1127 bimg = new BufferedImage(biw, bih, 1128 BufferedImage.TYPE_INT_RGB); 1129 Graphics2D big = bimg.createGraphics(); 1130 big.drawImage(surf.bimg, 0, 0, null); 1131 } 1132 double z = Math.min(w, h) * zoom; 1133 if ((type & OVAL) != 0) { 1134 shape = new Ellipse2D.Double(w / 2 - z / 2, h / 2 - z / 2, z, 1135 z); 1136 } else if ((type & ARC) != 0) { 1137 shape = new Arc2D.Double(-100, -100, w + 200, h + 200, 90, 1138 extent, Arc2D.PIE); 1139 extent -= eIncr; 1140 } else if ((type & RECT) != 0) { 1141 if ((type & WID) != 0) { 1142 shape = new Rectangle2D.Double(w / 2 - z / 2, 0, z, h); 1143 } else if ((type & HEI) != 0) { 1144 shape = new Rectangle2D.Double(0, h / 2 - z / 2, w, z); 1145 } else { 1146 shape = new Rectangle2D.Double(w / 2 - z / 2, h / 2 - z 1147 / 2, z, z); 1148 } 1149 } 1150 zoom += zIncr; 1151 } 1152 1153 @Override 1154 public void render(int w, int h, Graphics2D g2) { 1155 g2.clip(shape); 1156 g2.drawImage(bimg, 0, 0, null); 1157 } 1158 1159 @Override 1160 public int getBegin() { 1161 return beginning; 1162 } 1163 1164 @Override 1165 public int getEnd() { 1166 return ending; 1167 } 1168 } // End CoE class 1169 1170 1171 /** 1172 * Dither Dissolve Effect. For each successive step in the animation, 1173 * a pseudo-random starting horizontal position is chosen using list, 1174 * and then the corresponding points created from xlist and ylist are 1175 * blacked out for the current "chunk". The x and y chunk starting 1176 * positions are each incremented by the associated chunk size, and 1177 * this process is repeated for the number of "steps" in the 1178 * animation, causing an equal number of pseudo-randomly picked 1179 * "blocks" to be blacked out during each step of the animation. 1180 */ 1181 static class DdE implements Part { 1182 private final Surface surf; 1183 private int beginning, ending; 1184 private BufferedImage bimg; 1185 private Graphics2D big; 1186 private List<Integer> list, xlist, ylist; 1187 private int xeNum, yeNum; // element number 1188 private int xcSize, ycSize; // chunk size 1189 private int inc; 1190 private int blocksize; 1191 1192 public DdE(int beg, int end, int blocksize, Surface surf) { 1193 this.beginning = beg; 1194 this.ending = end; 1195 this.blocksize = blocksize; 1196 this.surf = surf; 1197 } 1198 1199 private void createShuffledLists() { 1200 int width = bimg.getWidth(); 1201 int height = bimg.getHeight(); 1202 xlist = new ArrayList<Integer>(width); 1203 ylist = new ArrayList<Integer>(height); 1204 list = new ArrayList<Integer>(ending - beginning + 1); 1205 for (int i = 0; i < width; i++) { 1206 xlist.add(i, i); 1207 } 1208 for (int i = 0; i < height; i++) { 1209 ylist.add(i, i); 1210 } 1211 for (int i = 0; i < (ending - beginning + 1); i++) { 1212 list.add(i, i); 1213 } 1214 java.util.Collections.shuffle(xlist); 1215 java.util.Collections.shuffle(ylist); 1216 java.util.Collections.shuffle(list); 1217 } 1218 1219 @Override 1220 public void reset(int w, int h) { 1221 bimg = null; 1222 } 1223 1224 @Override 1225 public void step(int w, int h) { 1226 if (inc > ending) { 1227 bimg = null; 1228 } 1229 if (bimg == null) { 1230 int biw = surf.bimg.getWidth(); 1231 int bih = surf.bimg.getHeight(); 1232 bimg = new BufferedImage(biw, bih, 1233 BufferedImage.TYPE_INT_RGB); 1234 createShuffledLists(); 1235 big = bimg.createGraphics(); 1236 big.drawImage(surf.bimg, 0, 0, null); 1237 xcSize = (xlist.size() / (ending - beginning)) + 1; 1238 ycSize = (ylist.size() / (ending - beginning)) + 1; 1239 xeNum = 0; 1240 inc = 0; 1241 } 1242 xeNum = xcSize * (list.get(inc)).intValue(); 1243 yeNum = -ycSize; 1244 inc++; 1245 } 1246 1247 @Override 1248 public void render(int w, int h, Graphics2D g2) { 1249 big.setColor(myBlack); 1250 1251 for (int k = 0; k <= (ending - beginning); k++) { 1252 if ((xeNum + xcSize) > xlist.size()) { 1253 xeNum = 0; 1254 } else { 1255 xeNum += xcSize; 1256 } 1257 yeNum += ycSize; 1258 1259 for (int i = xeNum; i < xeNum + xcSize && i < xlist.size(); 1260 i++) { 1261 for (int j = yeNum; j < yeNum + ycSize && j 1262 < ylist.size(); j++) { 1263 int xval = (xlist.get(i)).intValue(); 1264 int yval = (ylist.get(j)).intValue(); 1265 if (((xval % blocksize) == 0) && ((yval % blocksize) 1266 == 0)) { 1267 big.fillRect(xval, yval, blocksize, blocksize); 1268 } 1269 } 1270 } 1271 } 1272 1273 g2.drawImage(bimg, 0, 0, null); 1274 } 1275 1276 @Override 1277 public int getBegin() { 1278 return beginning; 1279 } 1280 1281 @Override 1282 public int getEnd() { 1283 return ending; 1284 } 1285 } // End DdE class 1286 1287 1288 /** 1289 * Subimage effect. Subimage the scene's buffered 1290 * image then rotate and scale down the subimages. 1291 */ 1292 static class SiE implements Part { 1293 private final Surface surf; 1294 private int beginning, ending; 1295 private BufferedImage bimg; 1296 private double rIncr, sIncr; 1297 private double scale, rotate; 1298 private int siw, sih; 1299 private List<BufferedImage> subs = new ArrayList<BufferedImage>(20); 1300 private List<Point> pts = new ArrayList<Point>(20); 1301 1302 public SiE(int siw, int sih, int beg, int end, Surface surf) { 1303 this.siw = siw; 1304 this.sih = sih; 1305 this.beginning = beg; 1306 this.ending = end; 1307 this.surf = surf; 1308 rIncr = 360.0 / (ending - beginning); 1309 sIncr = 1.0 / (ending - beginning); 1310 } 1311 1312 @Override 1313 public void reset(int w, int h) { 1314 scale = 1.0; 1315 rotate = 0.0; 1316 bimg = null; 1317 subs.clear(); 1318 pts.clear(); 1319 } 1320 1321 @Override 1322 public void step(int w, int h) { 1323 if (bimg == null) { 1324 int biw = surf.bimg.getWidth(); 1325 int bih = surf.bimg.getHeight(); 1326 bimg = new BufferedImage(biw, bih, 1327 BufferedImage.TYPE_INT_RGB); 1328 Graphics2D big = bimg.createGraphics(); 1329 big.drawImage(surf.bimg, 0, 0, null); 1330 for (int x = 0; x < w && scale > 0.0; x += siw) { 1331 int ww = x + siw < w ? siw : w - x; 1332 for (int y = 0; y < h; y += sih) { 1333 int hh = y + sih < h ? sih : h - y; 1334 subs.add(bimg.getSubimage(x, y, ww, hh)); 1335 pts.add(new Point(x, y)); 1336 } 1337 } 1338 } 1339 1340 rotate += rIncr; 1341 scale -= sIncr; 1342 } 1343 1344 @Override 1345 public void render(int w, int h, Graphics2D g2) { 1346 AffineTransform saveTx = g2.getTransform(); 1347 g2.setColor(myBlue); 1348 for (int i = 0; i < subs.size() && scale > 0.0; i++) { 1349 BufferedImage bi = subs.get(i); 1350 Point p = pts.get(i); 1351 int ww = bi.getWidth(); 1352 int hh = bi.getHeight(); 1353 AffineTransform at = new AffineTransform(); 1354 at.rotate(Math.toRadians(rotate), p.x + ww / 2, p.y + hh / 2); 1355 at.translate(p.x, p.y); 1356 at.scale(scale, scale); 1357 1358 Rectangle b1 = new Rectangle(0, 0, ww, hh); 1359 Shape shape = at.createTransformedShape(b1); 1360 Rectangle2D b2 = shape.getBounds2D(); 1361 double xx = (p.x + ww / 2) - (b2.getX() + b2.getWidth() / 2); 1362 double yy = (p.y + hh / 2) 1363 - (b2.getY() + b2.getHeight() / 2); 1364 AffineTransform toCenterAT = new AffineTransform(); 1365 toCenterAT.translate(xx, yy); 1366 toCenterAT.concatenate(at); 1367 1368 g2.setTransform(toCenterAT); 1369 g2.drawImage(bi, 0, 0, null); 1370 g2.draw(b1); 1371 } 1372 g2.setTransform(saveTx); 1373 } 1374 1375 @Override 1376 public int getBegin() { 1377 return beginning; 1378 } 1379 1380 @Override 1381 public int getEnd() { 1382 return ending; 1383 } 1384 } // End SiE class 1385 1386 1387 /** 1388 * Line Effect. Flattened ellipse with lines from the center 1389 * to the edge. Expand or collapse the ellipse. Fade in or out 1390 * the lines. 1391 */ 1392 static class LnE implements Part { 1393 1394 static final int INC = 1; 1395 static final int DEC = 2; 1396 static final int R = 4; // rotate 1397 static final int ZOOM = 8; // zoom 1398 static final int AC = 32; // AlphaComposite 1399 static final int RI = R | INC; 1400 static final int RD = R | DEC; 1401 static final int ZOOMI = ZOOM | INC; 1402 static final int ZOOMD = ZOOM | DEC; 1403 static final int ACI = AC | INC; 1404 static final int ACD = AC | DEC; 1405 private int beginning, ending; 1406 private double rIncr, rotate; 1407 private double zIncr, zoom; 1408 private List<Point2D.Double> pts = new ArrayList<Point2D.Double>(); 1409 private float alpha, aIncr; 1410 private int type; 1411 1412 public LnE(int type, int beg, int end) { 1413 this.type = type; 1414 this.beginning = beg; 1415 this.ending = end; 1416 float range = ending - beginning; 1417 rIncr = 360.0f / range; 1418 aIncr = 0.9f / range; 1419 zIncr = 2.0f / range; 1420 if ((type & DEC) != 0) { 1421 rIncr = -rIncr; 1422 aIncr = -aIncr; 1423 zIncr = -zIncr; 1424 } 1425 } 1426 1427 public void generatePts(int w, int h, double sizeF) { 1428 pts.clear(); 1429 double size = Math.min(w, h) * sizeF; 1430 Ellipse2D ellipse = new Ellipse2D.Double(w / 2 - size / 2, h / 2 - size 1431 / 2, size, size); 1432 PathIterator pi = ellipse.getPathIterator(null, 0.8); 1433 while (!pi.isDone()) { 1434 double[] pt = new double[6]; 1435 switch (pi.currentSegment(pt)) { 1436 case FlatteningPathIterator.SEG_MOVETO: 1437 case FlatteningPathIterator.SEG_LINETO: 1438 pts.add(new Point2D.Double(pt[0], pt[1])); 1439 } 1440 pi.next(); 1441 } 1442 } 1443 1444 @Override 1445 public void reset(int w, int h) { 1446 if ((type & DEC) != 0) { 1447 rotate = 360; 1448 alpha = 1.0f; 1449 zoom = 2.0; 1450 } else { 1451 rotate = alpha = 0; 1452 zoom = 0; 1453 } 1454 if ((type & ZOOM) == 0) { 1455 generatePts(w, h, 0.5); 1456 } 1457 } 1458 1459 @Override 1460 public void step(int w, int h) { 1461 if ((type & ZOOM) != 0) { 1462 generatePts(w, h, zoom += zIncr); 1463 } 1464 if ((type & RI) != 0 || (type & RI) != 0) { 1465 rotate += rIncr; 1466 } 1467 if ((type & ACI) != 0 || (type & ACD) != 0) { 1468 alpha += aIncr; 1469 } 1470 } 1471 1472 @Override 1473 public void render(int w, int h, Graphics2D g2) { 1474 Composite saveAC = null; 1475 if ((type & AC) != 0 && alpha >= 0 && alpha <= 1) { 1476 saveAC = g2.getComposite(); 1477 g2.setComposite(AlphaComposite.getInstance( 1478 AlphaComposite.SRC_OVER, alpha)); 1479 } 1480 AffineTransform saveTx = null; 1481 if ((type & R) != 0) { 1482 saveTx = g2.getTransform(); 1483 AffineTransform at = new AffineTransform(); 1484 at.rotate(Math.toRadians(rotate), w / 2, h / 2); 1485 g2.setTransform(at); 1486 } 1487 Point2D p1 = new Point2D.Double(w / 2, h / 2); 1488 g2.setColor(YELLOW); 1489 for (Point2D pt : pts) { 1490 g2.draw(new Line2D.Float(p1, pt)); 1491 } 1492 if (saveTx != null) { 1493 g2.setTransform(saveTx); 1494 } 1495 if (saveAC != null) { 1496 g2.setComposite(saveAC); 1497 } 1498 } 1499 1500 @Override 1501 public int getBegin() { 1502 return beginning; 1503 } 1504 1505 @Override 1506 public int getEnd() { 1507 return ending; 1508 } 1509 } // End LnE class 1510 1511 1512 /** 1513 * Template for Features & Contributors consisting of translating 1514 * blue and red rectangles and an image going from transparent to 1515 * opaque. 1516 */ 1517 static class Temp implements Part { 1518 1519 static final int NOANIM = 1; 1520 static final int RECT = 2; 1521 static final int IMG = 4; 1522 static final int RNA = RECT | NOANIM; 1523 static final int INA = IMG | NOANIM; 1524 private int beginning, ending; 1525 private float alpha, aIncr; 1526 private int type; 1527 private Rectangle rect1, rect2; 1528 private int x, y, xIncr, yIncr; 1529 private Image img; 1530 1531 public Temp(int type, Image img, int beg, int end) { 1532 this.type = type; 1533 this.img = img; 1534 this.beginning = beg; 1535 this.ending = end; 1536 aIncr = 0.9f / (ending - beginning); 1537 if ((type & NOANIM) != 0) { 1538 alpha = 1.0f; 1539 } 1540 } 1541 1542 @Override 1543 public void reset(int w, int h) { 1544 rect1 = new Rectangle(8, 20, w - 20, 30); 1545 rect2 = new Rectangle(20, 8, 30, h - 20); 1546 if ((type & NOANIM) == 0) { 1547 alpha = 0.0f; 1548 xIncr = w / (ending - beginning); 1549 yIncr = h / (ending - beginning); 1550 x = w + (int) (xIncr * 1.4); 1551 y = h + (int) (yIncr * 1.4); 1552 } 1553 } 1554 1555 @Override 1556 public void step(int w, int h) { 1557 if ((type & NOANIM) != 0) { 1558 return; 1559 } 1560 if ((type & RECT) != 0) { 1561 rect1.setLocation(x -= xIncr, 20); 1562 rect2.setLocation(20, y -= yIncr); 1563 } 1564 if ((type & IMG) != 0) { 1565 alpha += aIncr; 1566 } 1567 } 1568 1569 @Override 1570 public void render(int w, int h, Graphics2D g2) { 1571 if ((type & RECT) != 0) { 1572 g2.setColor(myBlue); 1573 g2.fill(rect1); 1574 g2.setColor(myRed); 1575 g2.fill(rect2); 1576 } 1577 if ((type & IMG) != 0) { 1578 Composite saveAC = g2.getComposite(); 1579 if (alpha >= 0 && alpha <= 1) { 1580 g2.setComposite(AlphaComposite.getInstance( 1581 AlphaComposite.SRC_OVER, alpha)); 1582 } 1583 g2.drawImage(img, 30, 30, null); 1584 g2.setComposite(saveAC); 1585 } 1586 } 1587 1588 @Override 1589 public int getBegin() { 1590 return beginning; 1591 } 1592 1593 @Override 1594 public int getEnd() { 1595 return ending; 1596 } 1597 } // End Temp class 1598 1599 1600 /** 1601 * Features of Java2D(TM). Single character advancement effect. 1602 */ 1603 static class Features implements Part { 1604 1605 static final int GRAPHICS = 0; 1606 static final int TEXT = 1; 1607 static final int IMAGES = 2; 1608 static final int COLOR = 3; 1609 static final Font font1 = new Font(Font.SERIF, Font.BOLD, 38); 1610 static final Font font2 = new Font(Font.SERIF, Font.PLAIN, 24); 1611 private final FontMetrics fm1; 1612 private final FontMetrics fm2; 1613 private static final String table[][] = { { "Graphics", "Antialiased rendering", 1614 "Bezier paths", 1615 "Transforms", "Compositing", "Stroking parameters" }, 1616 { "Text", "Extended font support", 1617 "Advanced text layout", "Dynamic font loading", 1618 "AttributeSets for font customization" }, 1619 { "Images", "Flexible image layouts", 1620 "Extended imaging operations", 1621 " Convolutions, Lookup Tables", 1622 "RenderableImage interface" }, 1623 { "Color", "ICC profile support", "Color conversion", 1624 "Arbitrary color spaces" } }; 1625 private String list[]; 1626 private int beginning, ending; 1627 private int strH; 1628 private int endIndex, listIndex; 1629 private List<String> v = new ArrayList<String>(); 1630 1631 public Features(int type, int beg, int end, Surface surf) { 1632 list = table[type]; 1633 this.beginning = beg; 1634 this.ending = end; 1635 fm1 = surf.getMetrics(font1); 1636 fm2 = surf.getMetrics(font2); 1637 } 1638 1639 @Override 1640 public void reset(int w, int h) { 1641 strH = (fm2.getAscent() + fm2.getDescent()); 1642 endIndex = 1; 1643 listIndex = 0; 1644 v.clear(); 1645 v.add(list[listIndex].substring(0, endIndex)); 1646 } 1647 1648 @Override 1649 public void step(int w, int h) { 1650 if (listIndex < list.length) { 1651 if (++endIndex > list[listIndex].length()) { 1652 if (++listIndex < list.length) { 1653 endIndex = 1; 1654 v.add(list[listIndex].substring(0, endIndex)); 1655 } 1656 } else { 1657 v.set(listIndex, list[listIndex].substring(0, endIndex)); 1658 } 1659 } 1660 } 1661 1662 @Override 1663 public void render(int w, int h, Graphics2D g2) { 1664 g2.setColor(myWhite); 1665 g2.setFont(font1); 1666 g2.drawString(v.get(0), 90, 85); 1667 g2.setFont(font2); 1668 for (int i = 1, y = 90; i < v.size(); i++) { 1669 g2.drawString(v.get(i), 120, y += strH); 1670 } 1671 } 1672 1673 @Override 1674 public int getBegin() { 1675 return beginning; 1676 } 1677 1678 @Override 1679 public int getEnd() { 1680 return ending; 1681 } 1682 } // End Features class 1683 1684 1685 /** 1686 * Scrolling text of Java2D(TM) contributors. 1687 */ 1688 static class Contributors implements Part { 1689 1690 private static final String members[] = { 1691 "Brian Lichtenwalter", "Jeannette Hung", 1692 "Thanh Nguyen", "Jim Graham", "Jerry Evans", 1693 "John Raley", "Michael Peirce", "Robert Kim", 1694 "Jennifer Ball", "Deborah Adair", "Paul Charlton", 1695 "Dmitry Feld", "Gregory Stone", "Richard Blanchard", 1696 "Link Perry", "Phil Race", "Vincent Hardy", 1697 "Parry Kejriwal", "Doug Felt", "Rekha Rangarajan", 1698 "Paula Patel", "Michael Bundschuh", "Joe Warzecha", 1699 "Joey Beheler", "Aastha Bhardwaj", "Daniel Rice", 1700 "Chris Campbell", "Shinsuke Fukuda", "Dmitri Trembovetski", 1701 "Chet Haase", "Jennifer Godinez", "Nicholas Talian", 1702 "Raul Vera", "Ankit Patel", "Ilya Bagrak", 1703 "Praveen Mohan", "Rakesh Menon" 1704 }; 1705 private static final Font font = new Font(Font.SERIF, Font.PLAIN, 26); 1706 private final FontMetrics fm; 1707 private int beginning, ending; 1708 private int nStrs, strH, index, yh, height; 1709 private List<String> v = new ArrayList<String>(); 1710 private List<String> cast = 1711 new ArrayList<String>(members.length + 3); 1712 private int counter, cntMod; 1713 private GradientPaint gp; 1714 1715 public Contributors(int beg, int end, Surface surf) { 1716 this.beginning = beg; 1717 this.ending = end; 1718 fm = surf.getMetrics(font); 1719 java.util.Arrays.sort(members); 1720 cast.add("CONTRIBUTORS"); 1721 cast.add(" "); 1722 cast.addAll(Arrays.asList(members)); 1723 cast.add(" "); 1724 cast.add(" "); 1725 cntMod = (ending - beginning) / cast.size() - 1; 1726 } 1727 1728 @Override 1729 public void reset(int w, int h) { 1730 v.clear(); 1731 strH = (fm.getAscent() + fm.getDescent()); 1732 nStrs = (h - 40) / strH + 1; 1733 height = strH * (nStrs - 1) + 48; 1734 index = 0; 1735 gp = new GradientPaint(0, h / 2, WHITE, 0, h + 20, BLACK); 1736 counter = 0; 1737 } 1738 1739 @Override 1740 public void step(int w, int h) { 1741 if (counter++ % cntMod == 0) { 1742 if (index < cast.size()) { 1743 v.add(cast.get(index)); 1744 } 1745 if ((v.size() == nStrs || index >= cast.size()) && !v. 1746 isEmpty()) { 1747 v.remove(0); 1748 } 1749 ++index; 1750 } 1751 } 1752 1753 @Override 1754 public void render(int w, int h, Graphics2D g2) { 1755 g2.setPaint(gp); 1756 g2.setFont(font); 1757 double remainder = counter % cntMod; 1758 double incr = 1.0 - remainder / cntMod; 1759 incr = incr == 1.0 ? 0 : incr; 1760 int y = (int) (incr * strH); 1761 1762 if (index >= cast.size()) { 1763 y = yh + y; 1764 } else { 1765 y = yh = height - v.size() * strH + y; 1766 } 1767 for (String s : v) { 1768 g2.drawString(s, w / 2 - fm.stringWidth(s) / 2, y += strH); 1769 } 1770 } 1771 1772 @Override 1773 public int getBegin() { 1774 return beginning; 1775 } 1776 1777 @Override 1778 public int getEnd() { 1779 return ending; 1780 } 1781 } // End Contributors class 1782 } // End Surface class 1783 } // End Intro class 1784