Source Code Cross Referenced for JCanvas3D.java in  » 6.0-JDK-Modules » java-3d » com » sun » j3d » exp » swing » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » java 3d » com.sun.j3d.exp.swing 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $RCSfile: JCanvas3D.java,v $
003:         *
004:         * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
005:         *
006:         * Redistribution and use in source and binary forms, with or without
007:         * modification, are permitted provided that the following conditions
008:         * are met:
009:         *
010:         * - Redistribution of source code must retain the above copyright
011:         *   notice, this list of conditions and the following disclaimer.
012:         *
013:         * - Redistribution in binary form must reproduce the above copyright
014:         *   notice, this list of conditions and the following disclaimer in
015:         *   the documentation and/or other materials provided with the
016:         *   distribution.
017:         *
018:         * Neither the name of Sun Microsystems, Inc. or the names of
019:         * contributors may be used to endorse or promote products derived
020:         * from this software without specific prior written permission.
021:         *
022:         * This software is provided "AS IS," without a warranty of any
023:         * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
024:         * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
025:         * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
026:         * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
027:         * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
028:         * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
029:         * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
030:         * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
031:         * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
032:         * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
033:         * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
034:         * POSSIBILITY OF SUCH DAMAGES.
035:         *
036:         * You acknowledge that this software is not designed, licensed or
037:         * intended for use in the design, construction, operation or
038:         * maintenance of any nuclear facility.
039:         *
040:         * $Revision: 1.10 $
041:         * $Date: 2007/04/11 02:08:56 $
042:         * $State: Exp $
043:         */
044:
045:        package com.sun.j3d.exp.swing;
046:
047:        import com.sun.j3d.exp.swing.impl.AutoOffScreenCanvas3D;
048:        import java.awt.Dimension;
049:        import java.awt.EventQueue;
050:        import java.awt.GraphicsConfigTemplate;
051:        import java.awt.GraphicsConfiguration;
052:        import java.awt.GraphicsDevice;
053:        import java.awt.GraphicsEnvironment;
054:        import java.awt.Rectangle;
055:        import java.awt.image.BufferedImage;
056:        import java.lang.reflect.InvocationTargetException;
057:        import javax.media.j3d.Canvas3D;
058:        import javax.media.j3d.GraphicsConfigTemplate3D;
059:        import javax.swing.JPanel;
060:        import javax.swing.event.AncestorListener;
061:
062:        /**
063:         * This class provides a lightweight capability to Java 3D. The component
064:         * handles bidirectional messaging between swing and Java 3D so that repaint
065:         * ordonned by swing are sent to the universe if necessary and refreshes from
066:         * the universe are painted accordingly. In order to get responsive interfaces
067:         * during layout changes, the canvas has a feature (disabled by default) that
068:         * lets true resizes occur only after a timer expires. Images between real
069:         * resizes can eventually be slightly wrong and pixelated, but their display
070:         * will be stutterless.<br>
071:         * Lightweight canvas also handles redirection to heavyweight canvas for the
072:         * following events:<br>
073:         * - InputMethodEvent<br>
074:         * - KeyEvent<br>
075:         * - FocusEvent<br>
076:         * - ComponentKeyEvent<br>
077:         * - MouseWheelEvent<br>
078:         * - MouseEvent<br>
079:         * - MouseMotionEvent<br>
080:         * <br>
081:         * <br>
082:         * When Swing is waiting for a canvas to be retrieved and that canvas is in
083:         * rendering stage,a loop takes place, which includes small calls to wait().
084:         * The canvas status is tested for readiness before and after the wait(). If
085:         * the canvas is not ready to be retrieved after the wait(), counter is
086:         * decremented and control is given back to awt thread, which will repaint old
087:         * buffer. If the loop goes over a certain amount of iterations, the canvas is
088:         * declared 'crashed' and won't be updated anymore. This was done so that a
089:         * crashed canvas/universe does not remove control over your GUI and does not
090:         * leave you with a frozen application. In current implementation, the delay
091:         * before a canvas is declared crashed is of :<br>
092:         * <code>30  Math.max(20.0, getView().getMinimumFrameCycleTime() )</code>
093:         *
094:         * @author Frederic 'pepe' Barachant
095:         *
096:         * @see getLightweightComponent()
097:         * @see setResizeValidationDelay()
098:         * @see setResizeMode()
099:         *
100:         * @since Java 3D 1.5
101:         */
102:        public class JCanvas3D extends JPanel implements  AncestorListener {
103:            /**
104:             * Resizing the canvas or component will be done immediately. This
105:             * operation might take some time and make the application look sluggish.
106:             *
107:             * @see setResizeMode()
108:             */
109:            public final static int RESIZE_IMMEDIATELY = 0;
110:
111:            /**
112:             * Resizing the canvas or component will be done if no resizing
113:             * occurs after expiration of a certain delay. Rendering will be
114:             * eventually stretched or deformed. It can be useful on certain
115:             * applications where smooth update of UI during layout is needed or
116:             * desired.
117:             *
118:             * @see setResizeMode()
119:             */
120:            public final static int RESIZE_DELAYED = 1;
121:
122:            //TODO: FBA: this had been taken from javax.media.j3d.Screen3D. When/IF proper dpi handling comes one day, that part will have to be changed also for consistency
123:            /** size of a pixel */
124:            private static double METERS_PER_PIXEL = 0.0254 / 90.0;
125:
126:            /** the template to be used for this canvas */
127:            private GraphicsConfigTemplate3D template;
128:
129:            /** the graphics configuration used for this canvas */
130:            private GraphicsConfiguration graphicsConfig;
131:
132:            /** The canvas that is linked to the component. */
133:            private InternalCanvas3D canvas;
134:
135:            /** flag indicating that the JCanvas3D has been added to a container */
136:            private boolean hasBeenAdded = false;
137:
138:            /** The resize mode currently being used. */
139:            int resizeMode;
140:
141:            /**
142:             * the idle delay that will trigger a real resize. ('idle' being
143:             * the lack of resizing action from the user)
144:             */
145:            int resizeValidationDelay;
146:
147:            /** the device to be used by this canvas */
148:            private GraphicsDevice device;
149:
150:            //TODO: FBA: the constructor below should be callable. Code should be changed so that it is possible, in order for the canvas to be useable into netbeans.
151:            //TODO: FBA: create a netbeans module that installs J3D as a library and the JCanvas3D as a new item in a new J3D category of the swing palette (take from the java.net swash project)
152:
153:            /**
154:             * Constructs and initializes a new JCanvas3D object that Java 3D
155:             * can render into. The screen device is obtained from
156:             * <code>GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()</code>,
157:             * which might not be the one you should use if you are in a multiscreen environment.
158:             * The JCanvas3D is constructed using the following default parameters:<br>
159:             * resize mode : RESIZE_IMMEDIATELY<br>
160:             * validation delay : 100ms<br>
161:             * double buffer enable : false<br>
162:             * stereo enable : false<br>
163:             */
164:            public JCanvas3D() {
165:                this (null, GraphicsEnvironment.getLocalGraphicsEnvironment()
166:                        .getDefaultScreenDevice());
167:            }
168:
169:            /**
170:             * Constructs and initializes a new Canvas3D object that Java 3D
171:             * can render into, using the specified graphics device.
172:             *
173:             * @param device the screen graphics device that will be used to construct
174:             *        a GraphicsConfiguration.
175:             */
176:            public JCanvas3D(GraphicsDevice device) {
177:                this (null, device);
178:            }
179:
180:            /**
181:             * Constructs and initializes a new Canvas3D object that Java 3D
182:             * can render into, using the specified template.
183:             * The screen device is obtained from
184:             * <code>GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()</code>,
185:             * which might not be the one you should use if you are
186:             * in a multiscreen environment.
187:             *
188:             * @param template The template that will be used to construct a
189:             *        GraphicsConfiguration. The stereo and doublebuffer properties
190:             *        are forced to UNNECESSARY.
191:             */
192:            public JCanvas3D(GraphicsConfigTemplate3D template) {
193:                this (template, GraphicsEnvironment
194:                        .getLocalGraphicsEnvironment().getDefaultScreenDevice());
195:            }
196:
197:            /**
198:             * Constructs and initializes a new Canvas3D object that Java 3D
199:             * can render into, using the specified template and graphics device.
200:             *
201:             * @param template The template that will be used to construct a
202:             *        GraphicsConfiguration. The stereo and doublebuffer properties
203:             *        are forced to UNNECESSARY.
204:             * @param device the screen graphics device that will be used to construct
205:             *        a GraphicsConfiguration in conjunction with the template.
206:             */
207:            public JCanvas3D(GraphicsConfigTemplate3D template,
208:                    GraphicsDevice device) {
209:                this .device = device;
210:                this .template = new GraphicsConfigTemplate3D();
211:
212:                if (template != null) {
213:                    // Clone template (it would be easier if GCT3D were cloneable)
214:                    this .template.setRedSize(template.getRedSize());
215:                    this .template.setGreenSize(template.getGreenSize());
216:                    this .template.setBlueSize(template.getBlueSize());
217:                    this .template.setDepthSize(template.getDepthSize());
218:                    this .template.setSceneAntialiasing(template
219:                            .getSceneAntialiasing());
220:                    this .template.setStencilSize(template.getStencilSize());
221:                    //            this.template.setDoubleBuffer(template.getDoubleBuffer());
222:                    //            this.template.setStereo(template.getStereo());
223:                }
224:
225:                // Force double-buffer and stereo to UNNECESSARY
226:                this .template.setStereo(GraphicsConfigTemplate.UNNECESSARY);
227:                this .template
228:                        .setDoubleBuffer(GraphicsConfigTemplate.UNNECESSARY);
229:
230:                graphicsConfig = this .device
231:                        .getBestConfiguration(this .template);
232:
233:                addAncestorListener(this );
234:                setDoubleBuffered(false);
235:                setResizeMode(RESIZE_IMMEDIATELY);
236:                setResizeValidationDelay(100);
237:
238:                // so that key events and such can be received.
239:                setFocusable(true);
240:            }
241:
242:            /**
243:             * {@inheritDoc}
244:             *
245:             * @param event {@inheritDoc}
246:             */
247:            public void ancestorAdded(javax.swing.event.AncestorEvent event) {
248:                //        if ( true == isVisible(  ) ) // check if the component itself is visible.
249:                {
250:                    Dimension sz = getSize();
251:
252:                    if (0 == sz.width) {
253:                        sz.width = 100;
254:                    }
255:
256:                    if (0 == sz.height) {
257:                        sz.height = 100;
258:                    }
259:
260:                    createCanvas(sz.width, sz.height);
261:                    canvas.addNotifyFlag = true; // make it so that i can call addNotify() without being rejected.
262:                    canvas.addNotify();
263:                    hasBeenAdded = true;
264:                }
265:            }
266:
267:            /**
268:             * {@inheritDoc}
269:             *
270:             * @param event {@inheritDoc}
271:             */
272:            public void ancestorMoved(javax.swing.event.AncestorEvent event) {
273:            }
274:
275:            /**
276:             * {@inheritDoc}
277:             *
278:             * @param event {@inheritDoc}
279:             */
280:            public void ancestorRemoved(javax.swing.event.AncestorEvent event) {
281:                hasBeenAdded = false;
282:                canvas.removeNotify();
283:            }
284:
285:            /**
286:             * Computes the physical dimensions of the screen in space.
287:             */
288:            private void computePhysicalDimensions() {
289:                // Fix to Issue : 433 - JCanvas3D crashed when using jogl pipe.
290:                Rectangle screenRect = this .graphicsConfig.getBounds();
291:                int screenWidth = (int) screenRect.getWidth();
292:                int screenHeight = (int) screenRect.getHeight();
293:                canvas.getScreen3D().setSize(screenWidth, screenHeight);
294:                canvas.getScreen3D().setPhysicalScreenWidth(
295:                        ((double) screenWidth) * METERS_PER_PIXEL);
296:                canvas.getScreen3D().setPhysicalScreenHeight(
297:                        ((double) screenHeight) * METERS_PER_PIXEL);
298:            }
299:
300:            /**
301:             * Creates a heavyweight canvas and initializes it, or changes the
302:             * size of the current one if present. Current heavyweight canvas is
303:             * changed only if size is different from the actual one. No canvas is
304:             * created if this component has no parent, that is, was not added to a
305:             * container.
306:             *
307:             * @param width the width of the canvas to create.
308:             * @param height the height of the canvas to create.
309:             */
310:            void createCanvas(int width, int height) {
311:                if (getParent() == null) {
312:                    return;
313:                }
314:
315:                if (null != canvas) {
316:                    // i had a canvas, i need to check if i really need to change it
317:                    if ((width != canvas.getWidth())
318:                            || (height != canvas.getHeight())) {
319:                        if ((null != canvas.getOffScreenBuffer())
320:                                && (null != canvas.getOffScreenBuffer()
321:                                        .getImage())) {
322:                            canvas.getOffScreenBuffer().getImage().flush(); // flushing so that eventual resources are freed.
323:                        }
324:                    } else {
325:                        return;
326:                    }
327:                } else {
328:                    // no canvas, i have to create it.
329:                    canvas = new InternalCanvas3D(this .graphicsConfig, this );
330:                }
331:
332:                createOffScreenBuffer(width, height); // whatever happened right above, i need to create the offscreen buffer.
333:            }
334:
335:            /**
336:             * Creates an offscreen buffer to be attached to the heavyweight
337:             * buffer. Buffer is created 'byreference'
338:             *
339:             * @param width the width of the buffer.
340:             * @param height the height of the buffer.
341:             */
342:            private void createOffScreenBuffer(int width, int height) {
343:                computePhysicalDimensions();
344:
345:                //        this.canvas.setDoubleBufferEnable( false );
346:                java.awt.image.BufferedImage bImage = new java.awt.image.BufferedImage(
347:                        width, height,
348:                        java.awt.image.BufferedImage.TYPE_INT_ARGB);
349:                javax.media.j3d.ImageComponent2D image = new javax.media.j3d.ImageComponent2D(
350:                        javax.media.j3d.ImageComponent2D.FORMAT_RGBA8, bImage,
351:                        true, false);
352:                image.setCapability(image.ALLOW_IMAGE_READ);
353:                image.setCapability(image.ALLOW_IMAGE_WRITE);
354:
355:                this .canvas.stopRenderer();
356:
357:                // offscreenrendering might occur even if the renderer is stopped. For that reason, i'm waiting for an hypothetical offscreen render to finish before setting offscreen rendering.
358:                // Otherwise, rendering will stop with an exception.
359:                this .canvas.waitForOffScreenRendering();
360:
361:                this .canvas.setOffScreenBuffer(image);
362:                this .canvas.startRenderer();
363:            }
364:
365:            /**
366:             * Returns the offscreen heavyweight canvas of that lightweight
367:             * component.
368:             *
369:             * @return the heavyweight canvas that lies in the deepness of this
370:             *         Component.
371:             */
372:            public Canvas3D getOffscreenCanvas3D() {
373:                if (null == this .canvas) {
374:                    createCanvas(getWidth(), getHeight());
375:                }
376:
377:                return this .canvas;
378:            }
379:
380:            /**
381:             * Retrieves the resize mode for that component.
382:             * 
383:             * @return the resize mode, which can be one of RESIZE_IMMEDIATELY or
384:             *         RESIZE_DELAYED
385:             */
386:            public int getResizeMode() {
387:                return resizeMode;
388:            }
389:
390:            /**
391:             * Retrieves the validation delay for that canvas, whatever the
392:             * resize mode is set to.
393:             *
394:             * @return the validation delay.
395:             */
396:            public int getResizeValidationDelay() {
397:                return resizeValidationDelay;
398:            }
399:
400:            /**
401:             * Paints the result of the rendering. If the rendered buffer is
402:             * not useable (render thread being between [code]postRender()[/code] and
403:             * [code]postSwap()[/code]), it will wait for it to be ready. Otherwise it
404:             * will directly paint the previous buffer.
405:             *
406:             * @param g {@inheritDoc}
407:             */
408:            public void paintComponent(java.awt.Graphics g) {
409:                super .paintComponent(g); //paint background
410:
411:                // Wait for and display image if JCanvas3D was added to an ancestor
412:                if (hasBeenAdded) {
413:                    if ((false == canvas.canvasCrashed)
414:                            && (true == canvas.isRendererRunning())) {
415:                        //            System.err.println("paintComponentWaitforSwap");
416:                        canvas.waitForSwap();
417:
418:                        //            System.err.println("wait is over");
419:                    }
420:
421:                    if (null != canvas.bi) {
422:                        // can eventually be null if the canvas did not send the result in the desired timeframe
423:                        // for first render. In that case, we don't paint and keep the background as-is.
424:                        g.drawImage(canvas.bi, 0, 0, getWidth(), getHeight(),
425:                                null);
426:                    }
427:                }
428:            }
429:
430:            /**
431:             * Redirects event to canvas and to superclass.
432:             *
433:             * @param e {@inheritDoc}
434:             */
435:            protected void processComponentKeyEvent(java.awt.event.KeyEvent e) {
436:                super .processComponentKeyEvent(e);
437:
438:                Object src = e.getSource();
439:                e.setSource(canvas);
440:                canvas.processComponentEvent(e);
441:                e.setSource(src);
442:            }
443:
444:            /**
445:             * Redirects event to canvas and to superclass.
446:             *
447:             * @param e {@inheritDoc}
448:             */
449:            protected void processFocusEvent(java.awt.event.FocusEvent e) {
450:                super .processFocusEvent(e);
451:
452:                Object src = e.getSource();
453:                e.setSource(canvas);
454:                canvas.processFocusEvent(e);
455:                e.setSource(src);
456:            }
457:
458:            /**
459:             * Redirects event to canvas and to superclass.
460:             *
461:             * @param e {@inheritDoc}
462:             */
463:            protected void processInputMethodEvent(
464:                    java.awt.event.InputMethodEvent e) {
465:                super .processInputMethodEvent(e);
466:
467:                Object src = e.getSource();
468:                e.setSource(canvas);
469:                canvas.processInputMethodEvent(e);
470:                e.setSource(src);
471:            }
472:
473:            /**
474:             * Redirects event to canvas and to superclass.
475:             *
476:             * @param e {@inheritDoc}
477:             */
478:            protected void processKeyEvent(java.awt.event.KeyEvent e) {
479:                super .processKeyEvent(e);
480:
481:                Object src = e.getSource();
482:                e.setSource(canvas);
483:                canvas.processKeyEvent(e);
484:                e.setSource(src);
485:            }
486:
487:            /**
488:             * Redirects event to canvas and to superclass.
489:             *
490:             * @param e {@inheritDoc}
491:             */
492:            protected void processMouseEvent(java.awt.event.MouseEvent e) {
493:                super .processMouseEvent(e);
494:
495:                Object src = e.getSource();
496:                e.setSource(canvas);
497:                canvas.processMouseEvent(e);
498:                e.setSource(src);
499:            }
500:
501:            /**
502:             * Redirects event to canvas and to superclass.
503:             *
504:             * @param e {@inheritDoc}
505:             */
506:            protected void processMouseMotionEvent(java.awt.event.MouseEvent e) {
507:                super .processMouseMotionEvent(e);
508:
509:                Object src = e.getSource();
510:                e.setSource(canvas);
511:                canvas.processMouseMotionEvent(e);
512:                e.setSource(src);
513:            }
514:
515:            /**
516:             * Redirects event to canvas and to superclass.
517:             *
518:             * @param e {@inheritDoc}
519:             */
520:            protected void processMouseWheelEvent(
521:                    java.awt.event.MouseWheelEvent e) {
522:                super .processMouseWheelEvent(e);
523:
524:                Object src = e.getSource();
525:                e.setSource(canvas);
526:                canvas.processMouseWheelEvent(e);
527:                e.setSource(src);
528:            }
529:
530:            /**
531:             * {@inheritDoc}
532:             *
533:             * @param x {@inheritDoc}
534:             * @param y {@inheritDoc}
535:             * @param width {@inheritDoc}
536:             * @param height {@inheritDoc}
537:             */
538:            public void setBounds(int x, int y, int width, int height) {
539:                super .setBounds(x, y, width, height);
540:
541:                if ((null == canvas) || (null == canvas.getOffScreenBuffer())
542:                        || (JCanvas3D.RESIZE_IMMEDIATELY == getResizeMode())) //whatever the resize mode, i create on first setbounds(). (not doing so would create a deadlock in DELAYED mode when trying to do the first paint
543:                {
544:                    createCanvas(width, height);
545:                } else if ((JCanvas3D.RESIZE_DELAYED == getResizeMode())
546:                        && ((null != canvas.getParent()) && (true == canvas
547:                                .getParent().isVisible()))) {
548:                    if ((null == canvas.resizeThread)
549:                            || (false == canvas.resizeThread.isAlive())) {
550:                        canvas.resizeThread = new ResizeThread(width, height,
551:                                getResizeValidationDelay(), this );
552:                        canvas.resizeThread.start();
553:                    } else {
554:                        canvas.resizeThread.setWidth(width);
555:                        canvas.resizeThread.setHeight(height);
556:                    }
557:                }
558:            }
559:
560:            /**
561:             * Sets resize mode to be used on this component. Resize mode
562:             * permits to have smoother canvas resizes. The time taken by a canvas to
563:             * be resized can be pretty long: renderer has to stop, current render has
564:             * to end, everything has to be initialized again, and after all that has
565:             * been done, renderer is started again, then the image is displayed once
566:             * rendered. Resize mode uses a timer to make those steps only after the
567:             * last refresh request occured. 'Latest refresh' is determined by the
568:             * amount of time between now and the last time you asked for a size
569:             * change. If that time expires, a real resize is done. In between, the
570:             * same size is rendered, but the drawn image is scaled down/up. This has
571:             * some drawbacks, as the image can appear blocked, imprecise, distorted,
572:             * incomplete for that while, but most of the time only some of the
573:             * drawbacks will be users will see nothing. Default delay is set to
574:             * 100ms, which is low enough for common human not to be able to really
575:             * see that the rendered image is scaled.
576:             * 
577:             * @param resizeMode can be one of RESIZE_IMMEDIATELY or RESIZE_DELAYED
578:             * @see #RESIZE_IMMEDIATELY
579:             * @see #RESIZE_DELAYED
580:             */
581:            public void setResizeMode(int resizeMode) {
582:                this .resizeMode = resizeMode;
583:            }
584:
585:            /**
586:             * Sets the validation delay for the component. The validation
587:             * delay is the maximum time allowed for the canvas resizing to occur
588:             * using rendered buffer scaling. Once that delay expired, the canvas is
589:             * resized at the lowest level possible, thus in the rendering pipeline.
590:             * Note: Changing this field is only useful if resize mode is set to
591:             * RESIZE_IMMEDIATELY or RESIZE_DELAYED
592:             * 
593:             * @param resizeValidationDelay the delay before a real resize would occur.
594:             * @see #RESIZE_IMMEDIATELY
595:             * @see #RESIZE_DELAYED
596:             */
597:            public void setResizeValidationDelay(int resizeValidationDelay) {
598:                this .resizeValidationDelay = resizeValidationDelay;
599:            }
600:
601:            /**
602:             * This class is the internal Canvas3D that is used and sent to
603:             * Java 3D. It is remote controlled through JCanvas3D and is modified to be
604:             * able to tell the lightweight component when refreshes are needed.
605:             */
606:            static class InternalCanvas3D extends Canvas3D implements 
607:                    AutoOffScreenCanvas3D {
608:
609:                // These two constants define the maximum amount of time
610:                // to wait for the readback of the off-screen buffer to complete.
611:                // The total time is MAX_WAIT_LOOPS * MAX_WAIT_TIME msec.
612:                private static final int MAX_WAIT_LOOPS = 5;
613:                private static final long MAX_WAIT_TIME = 100;
614:
615:                /**
616:                 * the bufferedImage that will be displayed as the result
617:                 * of the computations.
618:                 */
619:                BufferedImage bi = null;
620:
621:                /**
622:                 * This is the lightweight canvas that is linked to that
623:                 * offscreen canvas.
624:                 */
625:                JCanvas3D lwCanvas;
626:
627:                /**
628:                 * If delayed resizing is selected, a thread handling
629:                 * resising will be started.
630:                 */
631:                ResizeThread resizeThread;
632:
633:                /**
634:                 * flag used to sort a call to addnotify() from user and
635:                 * from the lightweight component. Lightweight component calls
636:                 * addNotify() so that the rendering begins and uses normal routines,
637:                 * but this is a method that user must not call.
638:                 */
639:                boolean addNotifyFlag;
640:
641:                /**
642:                 * flag indicating that the canvas crashed in a way or an
643:                 * other, making swing to wait for the swap for much too long.
644:                 */
645:                protected boolean canvasCrashed;
646:
647:                /**
648:                 * flag used to know when image can be painted or not. This
649:                 * is to avoid component potentially displaying a buffer with an
650:                 * unfinished blit. There is already a flag (imageReady) in Canvas3D
651:                 * that does this but it can't be used because of restrictions. This
652:                 * flag is not really fine grained, being set from end of postRender()
653:                 * to end of postSwap()
654:                 */
655:                boolean imageReadyBis;
656:
657:                /**
658:                 * Flag to indicate that the component is waiting for the
659:                 * canvas to acomplish its swap, and that the component has to be
660:                 * notified when done.
661:                 */
662:                boolean waitingForSwap;
663:
664:                /**
665:                 * Creates a new instance of JCanvas3D. Resize mode is set
666:                 * to RESIZE_IMMEDIATELY and validation delay to 100ms.
667:                 * 
668:                 * @param graphicsConfiguration The graphics configuration to be used.
669:                 * @param lwCanvas the lightweight canvas that is linked to that
670:                 *        heavyweight canvas.
671:                 */
672:                public InternalCanvas3D(
673:                        GraphicsConfiguration graphicsConfiguration,
674:                        JCanvas3D lwCanvas) {
675:                    super (graphicsConfiguration, true);
676:                    this .lwCanvas = lwCanvas;
677:                    imageReadyBis = false;
678:                    waitingForSwap = false;
679:                    addNotifyFlag = false;
680:                }
681:
682:                /**
683:                 * {@inheritDoc}
684:                 */
685:                public void addNotify() {
686:                    if (false == addNotifyFlag) {
687:                        throw new UnsupportedOperationException("CHANGE ME");
688:                    } else {
689:                        addNotifyFlag = false;
690:                        super .addNotify();
691:                    }
692:                }
693:
694:                /**
695:                 * Normally, returns the parent of that component. As the
696:                 * canvas ought to never be added to any component, it has no parent.
697:                 * Java 3D expects it to have a parent for some operations, so we in
698:                 * fact cheat it by returning the parent of the lightweight component.
699:                 *
700:                 * @return the parent of the lightweight component, if any. Returns
701:                 *         null if the component is not created or if it has no
702:                 *         parent.
703:                 */
704:                public java.awt.Container getParent() {
705:                    if (null == this .lwCanvas) {
706:                        return null;
707:                    }
708:
709:                    return this .lwCanvas.getParent();
710:                }
711:
712:                /**
713:                 * Blocks the retrieval of the render buffer.
714:                 */
715:                public void postRender() {
716:                    imageReadyBis = false;
717:                }
718:
719:                /**
720:                 * Retrieves the buffer from canvas, if possible, and
721:                 * calls/notifies component to be repainted, if necessary.
722:                 */
723:                synchronized public void postSwap() {
724:                    if (true == isRendererRunning()) { // as weird as it can look, there can be postswaps without rendered running. (?!!) Anyway, in that case we should not refresh.
725:                        bi = getOffScreenBuffer().getImage();
726:                        imageReadyBis = true;
727:
728:                        if (false == waitingForSwap) {
729:                            //                    System.err.println("repaint " + System.currentTimeMillis());
730:                            this .lwCanvas.repaint();
731:                        } else {
732:                            notify();
733:                        }
734:                    } else {
735:                        //                System.err.println("SWAP WITHOUT RENDERER RUNNING");
736:                    }
737:                }
738:
739:                /**
740:                 * Overriden so that the JComponent can access it.
741:                 *
742:                 * @param e {@inheritDoc}
743:                 */
744:                protected void processComponentEvent(
745:                        java.awt.event.ComponentEvent e) {
746:                    super .processComponentEvent(e);
747:                }
748:
749:                /**
750:                 * Overriden so that the JComponent can access it.
751:                 *
752:                 * @param e {@inheritDoc}
753:                 */
754:                protected void processFocusEvent(java.awt.event.FocusEvent e) {
755:                    super .processFocusEvent(e);
756:                }
757:
758:                /**
759:                 * Overriden so that the JComponent can access it.
760:                 *
761:                 * @param e {@inheritDoc}
762:                 */
763:                protected void processInputMethodEvent(
764:                        java.awt.event.InputMethodEvent e) {
765:                    super .processInputMethodEvent(e);
766:                }
767:
768:                /**
769:                 * Overriden so that the JComponent can access it.
770:                 *
771:                 * @param e {@inheritDoc}
772:                 */
773:                protected void processKeyEvent(java.awt.event.KeyEvent e) {
774:                    super .processKeyEvent(e);
775:                }
776:
777:                /**
778:                 * Overriden so that the JComponent can access it.
779:                 *
780:                 * @param e {@inheritDoc}
781:                 */
782:                protected void processMouseEvent(java.awt.event.MouseEvent e) {
783:                    super .processMouseEvent(e);
784:                }
785:
786:                /**
787:                 * Overriden so that the JComponent can access it.
788:                 *
789:                 * @param e {@inheritDoc}
790:                 */
791:                protected void processMouseMotionEvent(
792:                        java.awt.event.MouseEvent e) {
793:                    super .processMouseMotionEvent(e);
794:                }
795:
796:                /**
797:                 * Overriden so that the JComponent can access it.
798:                 *
799:                 * @param e {@inheritDoc}
800:                 */
801:                protected void processMouseWheelEvent(
802:                        java.awt.event.MouseWheelEvent e) {
803:                    super .processMouseWheelEvent(e);
804:                }
805:
806:                /**
807:                 * If the Canvas is in a state that forbids the retrieving
808:                 * of the buffer, wait a bit before trying again.
809:                 */
810:                synchronized void waitForSwap() {
811:                    int counter = MAX_WAIT_LOOPS;
812:                    while (false == imageReadyBis) {
813:                        try {
814:                            waitingForSwap = true;
815:                            wait(MAX_WAIT_TIME);
816:                            waitingForSwap = false;
817:
818:                            if (!imageReadyBis && --counter <= 0) {
819:                                //if i've waited too long for the canvas to be there, let us declare it crashed.
820:                                System.err.println("CANVAS CRASHED!!!");
821:                                canvasCrashed = true;
822:                                return;
823:                            }
824:                        } catch (InterruptedException ex) {
825:                            System.err.println(ex);
826:                        }
827:                    }
828:                }
829:
830:            }
831:
832:            /**
833:             * This Runnable is the class used when the canvas has to be
834:             * resized.
835:             */
836:            static class ResizeSwingRunnable implements  Runnable {
837:                /** The component that is displaying the canvas */
838:                JCanvas3D canvas;
839:
840:                /** latest height that was requested */
841:                int height;
842:
843:                /** latest width that was requested */
844:                int width;
845:
846:                /**
847:                 * Creates a new ResizeSwingRunnable object.
848:                 */
849:                private ResizeSwingRunnable() {
850:                }
851:
852:                /**
853:                 * Creates a new ResizeSwingRunnable object.
854:                 *
855:                 * @param canvas the canvas to check
856:                 * @param width the width that is requested
857:                 * @param height the height that is requested
858:                 */
859:                public ResizeSwingRunnable(JCanvas3D canvas, int width,
860:                        int height) {
861:                    this .canvas = canvas;
862:                    this .width = width;
863:                    this .height = height;
864:                }
865:
866:                /**
867:                 * {@inheritDoc}
868:                 */
869:                public void run() {
870:                    canvas.createCanvas(width, height);
871:                }
872:            }
873:
874:            /**
875:             * This Thread handles the resizing changes and handles the timer
876:             * up to the moment when the resizing has to really occur.
877:             */
878:            static class ResizeThread extends Thread {
879:                //TODO: refactor so that it can handle a list of canvases, delays and start delay date, and change to a singleton. Actually, each JCanvas3D that would have to resize would spawn its own thread, which ought to be seen as "a bad thing"
880:                /** the canvas that has to be checked */
881:                JCanvas3D canvas;
882:
883:                /** A flag indicating that since last check, size got changed again and the delay has to be reset */
884:                boolean sizeChanged;
885:
886:                /** the delay that has to occur between last size change and real resize */
887:                int delay;
888:
889:                /** latest height that was requested */
890:                int height;
891:
892:                /** latest width that was requested */
893:                int width;
894:
895:                /**
896:                 * Creates a new ResizeThread object.
897:                 */
898:                private ResizeThread() {
899:                }
900:
901:                /**
902:                 * Creates a new ResizeThread object.
903:                 *
904:                 * @param width initial width change
905:                 * @param height initial height change
906:                 * @param delay delay to be used
907:                 * @param canvas the canvas that has to be checked
908:                 */
909:                public ResizeThread(int width, int height, int delay,
910:                        JCanvas3D canvas) {
911:                    this .width = width;
912:                    this .height = height;
913:                    this .delay = delay;
914:                    this .sizeChanged = true;
915:                    this .canvas = canvas;
916:                }
917:
918:                /**
919:                 * returns the latest height that is being requested for change
920:                 *
921:                 * @return latest height requested
922:                 */
923:                public int getHeight() {
924:                    return height;
925:                }
926:
927:                /**
928:                 * returns the latest width that is being requested for change
929:                 *
930:                 * @return latest width requested
931:                 */
932:                public int getWidth() {
933:                    return width;
934:                }
935:
936:                /**
937:                 * {@inheritDoc}
938:                 */
939:                public void run() {
940:                    try {
941:                        while (true == sizeChanged) // the double loop is made so that if a change of size arrives while the canvas is already resizing, the same thread can keep up with subsequent resizes.
942:                        { // the effect of the double loop is to simplify some subtle race conditions at higher level.
943:
944:                            while (true == sizeChanged) {
945:                                sizeChanged = false;
946:                                Thread.sleep(delay); // while the thread sleeps, value can change. if value changes, flag will be true, and i'll have to wait again. if size does not change during the sleep, thread will quit and size will change.
947:                                //TODO: should i force a resize after a definite delay occured, so it does not stay zoomed too long ?
948:                            }
949:
950:                            try {
951:                                EventQueue
952:                                        .invokeAndWait(new ResizeSwingRunnable(
953:                                                canvas, width, height));
954:                            } catch (InterruptedException ie) {
955:                            } catch (InvocationTargetException ite) {
956:                            }
957:                        }
958:                    } catch (InterruptedException ie) {
959:                        //if i get interrupted, this is not important, i'll quit method.
960:                    }
961:                }
962:
963:                /**
964:                 * sets height. this has the effect of resetting the timeout.
965:                 *
966:                 * @param height the new height.
967:                 *
968:                 * @throws RuntimeException DOCUMENT ME!
969:                 */
970:                public void setHeight(int height) {
971:                    if (isAlive()) {
972:                        this .height = height;
973:                        sizeChanged = true;
974:                    } else {
975:                        throw new RuntimeException(
976:                                "Resizing order arrived to a dead resizing thread. Spawn a new one.");
977:                    }
978:                }
979:
980:                /**
981:                 * Sets width. This has the effect of resetting the timeout.
982:                 *
983:                 * @param width the new width.
984:                 *
985:                 * @throws RuntimeException DOCUMENT ME!
986:                 */
987:                public void setWidth(int width) {
988:                    if (isAlive()) {
989:                        this .width = width;
990:                        sizeChanged = true;
991:                    } else {
992:                        throw new RuntimeException(
993:                                "Resizing order arrived to a dead resizing thread. Spawn a new one.");
994:                    }
995:                }
996:            }
997:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.