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.demos.Mix; 33 34 35 import static java.awt.Color.BLACK; 36 import static java.awt.Color.BLUE; 37 import static java.awt.Color.GREEN; 38 import static java.awt.Color.RED; 39 import static java.awt.Color.WHITE; 40 import java.awt.AlphaComposite; 41 import java.awt.Color; 42 import java.awt.Component; 43 import java.awt.Dimension; 44 import java.awt.Font; 45 import java.awt.Graphics2D; 46 import java.awt.Rectangle; 47 import java.awt.Shape; 48 import java.awt.event.ActionEvent; 49 import java.awt.event.ActionListener; 50 import java.awt.font.FontRenderContext; 51 import java.awt.geom.AffineTransform; 52 import java.awt.geom.GeneralPath; 53 import java.awt.geom.Line2D; 54 import java.awt.geom.Path2D; 55 import java.awt.geom.PathIterator; 56 import java.awt.geom.Rectangle2D; 57 import java2d.ControlsSurface; 58 import java2d.CustomControls; 59 import javax.swing.JLabel; 60 import javax.swing.JTextField; 61 62 63 /** 64 * Generate a 3D text shape with GeneralPath, render a number of small 65 * multi-colored rectangles and then render the 3D text shape. 66 */ 67 @SuppressWarnings("serial") 68 public class Stars3D extends ControlsSurface { 69 70 private static Color colors[] = { RED, GREEN, WHITE }; 71 private static AffineTransform at = AffineTransform.getTranslateInstance(-5, 72 -5); 73 private Shape shape, tshape; 74 private Shape ribbon; 75 protected int fontSize = 72; 76 protected String text = "OpenJDK"; 77 protected int numStars = 300; 78 Stars3D()79 public Stars3D() { 80 setBackground(BLACK); 81 setControls(new Component[] { new DemoControls(this) }); 82 } 83 84 @Override render(int w, int h, Graphics2D g2)85 public void render(int w, int h, Graphics2D g2) { 86 87 Rectangle2D rect = new Rectangle2D.Double(); 88 for (int i = 0; i < numStars; i++) { 89 g2.setColor(colors[i % 3]); 90 g2.setComposite(AlphaComposite.getInstance( 91 AlphaComposite.SRC_OVER, (float) Math.random())); 92 rect.setRect(w * Math.random(), h * Math.random(), 2, 2); 93 g2.fill(rect); 94 } 95 96 FontRenderContext frc = g2.getFontRenderContext(); 97 Font font = new Font(Font.SERIF, Font.BOLD|Font.ITALIC, fontSize); 98 shape = font.createGlyphVector(frc, text).getOutline(); 99 tshape = at.createTransformedShape(shape); 100 PathIterator pi = shape.getPathIterator(null); 101 102 float seg[] = new float[6]; 103 float tseg[] = new float[6]; 104 105 GeneralPath working = new GeneralPath(Path2D.WIND_NON_ZERO); 106 float x = 0, y = 0; // Current point on the path 107 float tx = 0, ty = 0; // Transformed path point 108 float cx = 0, cy = 0; // Last moveTo point, for SEG_CLOSE 109 float tcx = 0, tcy = 0; // Transformed last moveTo point 110 111 // 112 // Iterate through the Shape and build the ribbon 113 // by adding general path objects. 114 // 115 while (!pi.isDone()) { 116 int segType = pi.currentSegment(seg); 117 switch (segType) { 118 case PathIterator.SEG_MOVETO: 119 at.transform(seg, 0, tseg, 0, 1); 120 x = seg[0]; 121 y = seg[1]; 122 tx = tseg[0]; 123 ty = tseg[1]; 124 cx = x; 125 cy = y; 126 tcx = tx; 127 tcy = ty; 128 break; 129 case PathIterator.SEG_LINETO: 130 at.transform(seg, 0, tseg, 0, 1); 131 if (Line2D.relativeCCW(x, y, tx, ty, seg[0], seg[1]) < 0) { 132 working.moveTo(x, y); 133 working.lineTo(seg[0], seg[1]); 134 working.lineTo(tseg[0], tseg[1]); 135 working.lineTo(tx, ty); 136 working.lineTo(x, y); 137 } else { 138 working.moveTo(x, y); 139 working.lineTo(tx, ty); 140 working.lineTo(tseg[0], tseg[1]); 141 working.lineTo(seg[0], seg[1]); 142 working.lineTo(x, y); 143 } 144 145 x = seg[0]; 146 y = seg[1]; 147 tx = tseg[0]; 148 ty = tseg[1]; 149 break; 150 151 case PathIterator.SEG_QUADTO: 152 at.transform(seg, 0, tseg, 0, 2); 153 if (Line2D.relativeCCW(x, y, tx, ty, seg[2], seg[3]) < 0) { 154 working.moveTo(x, y); 155 working.quadTo(seg[0], seg[1], 156 seg[2], seg[3]); 157 working.lineTo(tseg[2], tseg[3]); 158 working.quadTo(tseg[0], tseg[1], 159 tx, ty); 160 working.lineTo(x, y); 161 } else { 162 working.moveTo(x, y); 163 working.lineTo(tx, ty); 164 working.quadTo(tseg[0], tseg[1], 165 tseg[2], tseg[3]); 166 working.lineTo(seg[2], seg[3]); 167 working.quadTo(seg[0], seg[1], 168 x, y); 169 } 170 171 x = seg[2]; 172 y = seg[3]; 173 tx = tseg[2]; 174 ty = tseg[3]; 175 break; 176 177 case PathIterator.SEG_CUBICTO: 178 at.transform(seg, 0, tseg, 0, 3); 179 if (Line2D.relativeCCW(x, y, tx, ty, seg[4], seg[5]) < 0) { 180 working.moveTo(x, y); 181 working.curveTo(seg[0], seg[1], 182 seg[2], seg[3], 183 seg[4], seg[5]); 184 working.lineTo(tseg[4], tseg[5]); 185 working.curveTo(tseg[2], tseg[3], 186 tseg[0], tseg[1], 187 tx, ty); 188 working.lineTo(x, y); 189 } else { 190 working.moveTo(x, y); 191 working.lineTo(tx, ty); 192 working.curveTo(tseg[0], tseg[1], 193 tseg[2], tseg[3], 194 tseg[4], tseg[5]); 195 working.lineTo(seg[4], seg[5]); 196 working.curveTo(seg[2], seg[3], 197 seg[0], seg[1], 198 x, y); 199 } 200 201 x = seg[4]; 202 y = seg[5]; 203 tx = tseg[4]; 204 ty = tseg[5]; 205 break; 206 207 case PathIterator.SEG_CLOSE: 208 if (Line2D.relativeCCW(x, y, tx, ty, cx, cy) < 0) { 209 working.moveTo(x, y); 210 working.lineTo(cx, cy); 211 working.lineTo(tcx, tcy); 212 working.lineTo(tx, ty); 213 working.lineTo(x, y); 214 } else { 215 working.moveTo(x, y); 216 working.lineTo(tx, ty); 217 working.lineTo(tcx, tcy); 218 working.lineTo(cx, cy); 219 working.lineTo(x, y); 220 } 221 x = cx; 222 y = cy; 223 tx = tcx; 224 ty = tcy; 225 } 226 pi.next(); 227 } // while 228 ribbon = working; 229 230 if (composite != null) { 231 g2.setComposite(composite); 232 } else { 233 g2.setComposite(AlphaComposite.SrcOver); 234 } 235 Rectangle r = shape.getBounds(); 236 g2.translate(w * .5 - r.width * .5, h * .5 + r.height * .5); 237 238 g2.setColor(BLUE); 239 g2.fill(tshape); 240 g2.setColor(new Color(255, 255, 255, 200)); 241 g2.fill(ribbon); 242 243 g2.setColor(WHITE); 244 g2.fill(shape); 245 246 g2.setColor(BLUE); 247 g2.draw(shape); 248 } 249 main(String argv[])250 public static void main(String argv[]) { 251 createDemoFrame(new Stars3D()); 252 } 253 254 255 static class DemoControls extends CustomControls implements ActionListener { 256 257 Stars3D demo; 258 JTextField tf1, tf2; 259 260 @SuppressWarnings("LeakingThisInConstructor") DemoControls(Stars3D demo)261 public DemoControls(Stars3D demo) { 262 super(demo.name); 263 this.demo = demo; 264 JLabel l = new JLabel(" Text:"); 265 l.setForeground(BLACK); 266 add(l); 267 add(tf1 = new JTextField(demo.text)); 268 tf1.setPreferredSize(new Dimension(60, 20)); 269 tf1.addActionListener(this); 270 l = new JLabel(" Size:"); 271 l.setForeground(BLACK); 272 add(l); 273 add(tf2 = new JTextField(String.valueOf(demo.fontSize))); 274 tf2.setPreferredSize(new Dimension(30, 20)); 275 tf2.addActionListener(this); 276 } 277 278 @Override actionPerformed(ActionEvent e)279 public void actionPerformed(ActionEvent e) { 280 try { 281 if (e.getSource().equals(tf1)) { 282 demo.text = tf1.getText().trim(); 283 } else if (e.getSource().equals(tf2)) { 284 demo.fontSize = Integer.parseInt(tf2.getText().trim()); 285 if (demo.fontSize < 10) { 286 demo.fontSize = 10; 287 } 288 } 289 demo.repaint(); 290 } catch (Exception ignored) { 291 } 292 } 293 294 @Override getPreferredSize()295 public Dimension getPreferredSize() { 296 return new Dimension(200, 37); 297 } 298 299 @Override 300 @SuppressWarnings("SleepWhileHoldingLock") run()301 public void run() { 302 Thread me = Thread.currentThread(); 303 try { 304 Thread.sleep(999); 305 } catch (Exception e) { 306 return; 307 } 308 int length = getSize().width / 4; 309 int size[] = { length, length }; 310 String str[] = { "OpenJDK", "J2D" }; 311 while (thread == me) { 312 for (int i = 0; i < str.length; i++) { 313 demo.fontSize = size[i]; 314 tf2.setText(String.valueOf(demo.fontSize)); 315 tf1.setText(demo.text = str[i]); 316 demo.repaint(); 317 try { 318 Thread.sleep(5555); 319 } catch (InterruptedException e) { 320 return; 321 } 322 } 323 } 324 thread = null; 325 } 326 } // End DemoControls 327 } // End Stars3D 328 329