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