|
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 |
|
79 public Stars3D() { |
|
80 setBackground(BLACK); |
|
81 setControls(new Component[] { new DemoControls(this) }); |
|
82 } |
|
83 |
|
84 @Override |
|
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 |
|
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") |
|
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 |
|
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 |
|
295 public Dimension getPreferredSize() { |
|
296 return new Dimension(200, 37); |
|
297 } |
|
298 |
|
299 @Override |
|
300 @SuppressWarnings("SleepWhileHoldingLock") |
|
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 |