1 /*
2  * $RCSfile: VirtualUniverse.java,v $
3  *
4  * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6  *
7  * This code is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License version 2 only, as
9  * published by the Free Software Foundation.  Sun designates this
10  * particular file as subject to the "Classpath" exception as provided
11  * by Sun in the LICENSE file that accompanied this code.
12  *
13  * This code is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16  * version 2 for more details (a copy is included in the LICENSE file that
17  * accompanied this code).
18  *
19  * You should have received a copy of the GNU General Public License version
20  * 2 along with this work; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
24  * CA 95054 USA or visit www.sun.com if you need additional information or
25  * have any questions.
26  *
27  * $Revision: 1.17 $
28  * $Date: 2008/02/28 20:17:33 $
29  * $State: Exp $
30  */
31 
32 package javax.media.j3d;
33 
34 import java.util.Vector;
35 import java.util.ArrayList;
36 import java.util.Enumeration;
37 import java.util.HashSet;
38 import java.util.Iterator;
39 import java.util.Map;
40 import java.util.logging.Level;
41 import java.util.logging.Logger;
42 
43 /**
44  * A VirtualUniverse object is the top-level container for all scene
45  * graphs.  A virtual universe consists of a set of Locale objects,
46  * each of which has a high-resolution position within the virtual
47  * universe.  An application or applet may have more than one
48  * VirtualUniverse objects, but many applications will need only one.
49  * Virtual universes are separate entities in that no node object may
50  * exist in more than one virtual universe at any one time. Likewise,
51  * the objects in one virtual universe are not visible in, nor do they
52  * interact with objects in, any other virtual universe.
53  * <p>
54  * A VirtualUniverse object defines methods to enumerate its Locale
55  * objects and to remove them from the virtual universe.
56  *
57  * <p>
58  * For more information, see the
59  * <a href="doc-files/intro.html">Introduction to the Java 3D API</a> and
60  * <a href="doc-files/VirtualUniverse.html">Scene Graph Superstructure</a>
61  * documents.
62  *
63  * @see Locale
64  */
65 
66 public class VirtualUniverse extends Object {
67     // NOTE TO DEVELOPERS:
68     //
69     // Developers who modify Java 3D in any way should modify
70     // the auxiliary implementation vendor string in VersionInfo.java.
71     // See that file for instructions.
72 
73     // The global MasterControl object.  There is only one of these
74     // for all of Java 3D.
75     static MasterControl mc = null;
76 
77     // The lock to acquire before traversing the scene graph
78     Object sceneGraphLock = new Object();
79     Object behaviorLock = new Object();
80 
81     // A list of locales that are contained within this universe
82     Vector listOfLocales = new Vector();
83 
84     // The list of view platforms.
85     ArrayList viewPlatforms = new ArrayList();
86 
87 
88     // The cached list of vp's
89     Object[] viewPlatformList = null;
90 
91     // A flag that indicates that the list of view platforms has changed
92     boolean vpChanged = false;
93 
94     // The list of backgrounds
95     Vector backgrounds = new Vector();
96 
97     // The list of clips
98     Vector clips = new Vector();
99 
100     // The list of sounds
101     Vector sounds = new Vector();
102 
103     // The list of soundscapes
104     Vector soundscapes = new Vector();
105 
106     // The Behavior Scheduler Thread for this Virtual Universe.
107     BehaviorScheduler behaviorScheduler = null;
108 
109 
110     // The geometry structure for this Universe
111     GeometryStructure geometryStructure = null;
112 
113     // The transform structure for this Universe
114     TransformStructure transformStructure = null;
115 
116     // The behavior structure for this Universe
117     BehaviorStructure behaviorStructure = null;
118 
119     // The sound structure for this Universe
120     SoundStructure soundStructure = null;
121 
122     // The rendering attributes structure for this Universe
123     RenderingEnvironmentStructure renderingEnvironmentStructure = null;
124 
125     // Reference count of users of the RenderingEnvironmentStructure
126     int renderingEnvironmentStructureRefCount = 0;
127 
128     // This is a global counter for node id's.
129     long nodeIdCount = 0;
130 
131     // This is a global counter for view id's.
132     int viewIdCount = 0;
133 
134     // This is a vector of free nodeid's
135     Vector nodeIdFreeList = new Vector();
136 
137     // This is a vector of free viewid's
138     ArrayList viewIdFreeList = new ArrayList();
139 
140     // The number of nodes in this universe
141     int numNodes = 0;
142 
143     // The State object used when branch graphs are added
144     SetLiveState setLiveState;
145 
146     // This is an array of references to objects that need their mirror
147     // copies updated.  It is updated by the traverser and emptied by
148     // the view thread.
149     ObjectUpdate[] updateObjects = new ObjectUpdate[16];
150 
151     // The number of valid entries in updateObjects
152     int updateObjectsLen = 0;
153 
154     // A list of all mirror geometry object that are dirty
155     ArrayList dirtyGeomList = new ArrayList();
156 
157     // The current primary view for this universe
158     View currentView;
159 
160     // A flag to indicate that we are in a behavior routine
161     boolean inBehavior = false;
162 
163     // Flags to indicate if events need to be delivered
164     boolean enableComponent = false;
165     boolean enableFocus = false;
166     boolean enableKey = false;
167     boolean enableMouse = false;
168     boolean enableMouseMotion = false;
169     boolean enableMouseWheel = false;
170 
171     // Keep track of how many active View use this universe
172     int activeViewCount = 0;
173 
174     // Root ThreadGroup for creating Java 3D threads
175     static ThreadGroup rootThreadGroup;
176 
177     // Properties object for getProperties
178     private static J3dQueryProps properties = null;
179 
180     // Flag to indicate that user thread has to
181     // stop until MC completely register/unregister View.
182     View regViewWaiting = null;
183     View unRegViewWaiting = null;
184     boolean isSceneGraphLock = false;
185 
186     private Object waitLock = new Object();
187 
188     // Set of scene graph structure change listeners
189     private HashSet<GraphStructureChangeListener> structureChangeListenerSet = null;
190 
191     // Set of shader error listeners
192     private HashSet<ShaderErrorListener> shaderErrorListenerSet = null;
193     private ShaderErrorListener defaultShaderErrorListener =
194 	ShaderProgram.getDefaultErrorListener();
195 
196     // Set of rendering error listeners
197     private static HashSet<RenderingErrorListener> renderingErrorListenerSet = null;
198     private static RenderingErrorListener defaultRenderingErrorListener =
199 	Renderer.getDefaultErrorListener();
200 
201     /**
202      * Constructs a new VirtualUniverse.
203      */
VirtualUniverse()204     public VirtualUniverse() {
205 	setLiveState = new SetLiveState(this);
206 	initMCStructure();
207     }
208 
209 
initMCStructure()210     void initMCStructure() {
211 	if (geometryStructure != null) {
212 	    geometryStructure.cleanup();
213 	}
214         geometryStructure = new GeometryStructure(this);
215 	if (transformStructure != null) {
216 	    transformStructure.cleanup();
217 	}
218         transformStructure = new TransformStructure(this);
219 	if (behaviorStructure != null) {
220 	    behaviorStructure.cleanup();
221 	}
222         behaviorStructure = new BehaviorStructure(this);
223 	if (soundStructure != null) {
224 	    soundStructure.cleanup();
225 	}
226         soundStructure = new SoundStructure(this);
227 	if (renderingEnvironmentStructure != null) {
228 	    renderingEnvironmentStructure.cleanup();
229 	}
230         renderingEnvironmentStructure = new
231 	            RenderingEnvironmentStructure(this);
232 
233     }
234 
235     /**
236      * Initialize the native interface and anything else that needs
237      * to be initialized.
238      */
loadLibraries()239     static void loadLibraries() {
240 	// No need to do anything.  The act of calling any method in this
241 	// class is sufficient to cause the static MasterControl object
242 	// to be created which, in turn, loads the native libraries.
243     }
244 
245     static {
246         boolean isLoggableConfig = MasterControl.isCoreLoggable(Level.CONFIG);
247         Logger logger = MasterControl.getCoreLogger();
248 
249         // Print out version information unless this is a
250         // non-debuggable, release (fcs) build
251         if (isLoggableConfig || J3dDebug.devPhase || VersionInfo.isDebug) {
252             StringBuffer strBuf = new StringBuffer("3D ");
253 	    if (J3dDebug.devPhase) {
254 		strBuf.append("[dev] ");
255 	    }
VersionInfo.getVersion()256             strBuf.append(VersionInfo.getVersion());
257             String str = strBuf.toString();
258             if (isLoggableConfig) {
259                 logger.config(str);
260             } else {
261                 System.err.println(str);
System.err.println()262                 System.err.println();
263             }
264 	}
265 
266 	// Print out debugging information for debug builds
267 	if (isLoggableConfig || VersionInfo.isDebug) {
268             StringBuffer strBuf = new StringBuffer();
269             strBuf.append("Initializing 3D runtime system:\n").
270                     append("    version = ").
271                     append(VersionInfo.getVersion()).
272                     append("\n").
273                     append("    vendor = ").
274                     append(VersionInfo.getVendor()).
275                     append("\n").
276                     append("    specification.version = ").
277                     append(VersionInfo.getSpecificationVersion()).
278                     append("\n").
279                     append("    specification.vendor = ").
VersionInfo.getSpecificationVendor()280                     append(VersionInfo.getSpecificationVendor());
281             String str = strBuf.toString();
282             if (isLoggableConfig) {
283                 logger.config(str);
284             } else {
285                 System.err.println(str);
System.err.println()286                 System.err.println();
287             }
288 	}
289 
290 	// Java 3D cannot run in headless mode, so we will throw a
291 	// HeadlessException if isHeadless() is true. This avoids a
292 	// cryptic error message from MasterControl.loadLibraries().
293 	if (java.awt.GraphicsEnvironment.isHeadless()) {
java.awt.HeadlessException()294 	    throw new java.awt.HeadlessException();
295 	}
296 
297 	// Load the native libraries and create the static
298 	// MasterControl object
MasterControl.loadLibraries()299 	MasterControl.loadLibraries();
300 	mc = new MasterControl();
301 
302         // Print out debugging information for debug builds
303         if (isLoggableConfig || VersionInfo.isDebug) {
304             StringBuffer strBuf = new StringBuffer();
305             strBuf.append("3D system initialized\n").
306                     append("    rendering pipeline = ").
307                     append(Pipeline.getPipeline().getPipelineName());
308             String str = strBuf.toString();
309             if (isLoggableConfig) {
310                 logger.config(str);
311             } else {
312                 System.err.println(str);
System.err.println()313                 System.err.println();
314             }
315         }
316     }
317 
318     /**
319      * Adds a locale at the end of list of locales
320      * @param locale the locale to be added
321      */
addLocale(Locale locale)322     void addLocale(Locale locale) {
323 	listOfLocales.addElement(locale);
324     }
325 
326     /**
327      * Removes a Locale and its associates branch graphs from this
328      * universe.  All branch graphs within the specified Locale are
329      * detached, regardless of whether their ALLOW_DETACH capability
330      * bits are set.  The Locale is then marked as being dead: no
331      * branch graphs may subsequently be attached.
332      *
333      * @param locale the Locale to be removed.
334      *
335      * @exception IllegalArgumentException if the specified Locale is not
336      * attached to this VirtualUniverse.
337      *
338      * @since Java 3D 1.2
339      */
removeLocale(Locale locale)340     public void removeLocale(Locale locale) {
341 	if (locale.getVirtualUniverse() != this) {
342 	    throw new IllegalArgumentException(J3dI18N.getString("VirtualUniverse0"));
343 	}
344 
345 	listOfLocales.removeElement(locale);
346 	locale.removeFromUniverse();
347 	if (isEmpty()) {
348 	    VirtualUniverse.mc.postRequest(MasterControl.EMPTY_UNIVERSE,
349 					   this);
350 	}
351 	setLiveState.reset(null);
352     }
353 
354 
355     /**
356      * Removes all Locales and their associates branch graphs from
357      * this universe.  All branch graphs within each Locale are
358      * detached, regardless of whether their ALLOW_DETACH capability
359      * bits are set.  Each Locale is then marked as being dead: no
360      * branch graphs may subsequently be attached.  This method
361      * should be called by applications and applets to allow
362      * Java 3D to cleanup its resources.
363      *
364      * @since Java 3D 1.2
365      */
removeAllLocales()366     public void removeAllLocales() {
367 	// NOTE: this is safe because Locale.removeFromUniverse does not
368 	// remove the Locale from the listOfLocales
369 	int i;
370 
371 
372 	for (i = listOfLocales.size()-1; i > 0;  i--) {
373 	    ((Locale)listOfLocales.get(i)).removeFromUniverse();
374 	}
375 
376 	if (i >= 0) {
377 	    // We have to clear() the listOfLocales first before
378 	    // invoke the last removeFromUniverse() so that isEmpty()
379 	    // (call from View.deactivate() ) will return true and
380 	    // threads can destroy from MC.
381 	    Locale loc = (Locale) listOfLocales.get(0);
382 	    listOfLocales.clear();
383 	    loc.removeFromUniverse();
384 	}
385 	VirtualUniverse.mc.postRequest(MasterControl.EMPTY_UNIVERSE,
386 				       this);
387 
388 	setLiveState.reset(null);
389     }
390 
391 
392     /**
393      * Returns the enumeration object of all locales in this virtual universe.
394      * @return the enumeration object
395      */
getAllLocales()396     public Enumeration getAllLocales() {
397 	return this.listOfLocales.elements();
398     }
399 
400     /**
401      * Returns the number of locales.
402      * @return the count of locales
403      */
numLocales()404     public int numLocales() {
405 	return this.listOfLocales.size();
406     }
407 
408 
409     /**
410      * Sets the priority of all Java 3D threads to the specified
411      * value.  The default value is the priority of the thread that
412      * started Java 3D.
413      *
414      * @param priority the new thread priority
415      *
416      * @exception IllegalArgumentException if the priority is not in
417      * the range MIN_PRIORITY to MAX_PRIORITY
418      *
419      * @exception SecurityException if the priority is greater than
420      * that of the calling thread
421      *
422      * @since Java 3D 1.2
423      */
setJ3DThreadPriority(int priority)424     public static void setJ3DThreadPriority(int priority) {
425 	if (priority > Thread.MAX_PRIORITY) {
426 	    priority = Thread.MAX_PRIORITY;
427 	} else if (priority < Thread.MIN_PRIORITY) {
428 	    priority = Thread.MIN_PRIORITY;
429 	}
430 	VirtualUniverse.mc.setThreadPriority(priority);
431     }
432 
433 
434     /**
435      * Retrieves that priority of Java 3D's threads.
436      *
437      * @return the current priority of Java 3D's threads
438      *
439      * @since Java 3D 1.2
440      */
getJ3DThreadPriority()441     public static int getJ3DThreadPriority() {
442 	return VirtualUniverse.mc.getThreadPriority();
443     }
444 
445 
446     /**
447      * Returns a read-only Map object containing key-value pairs that
448      * define various global properties for Java 3D.  All of the keys
449      * are String objects.  The values are key-specific, but most will
450      * be String objects.
451      *
452      * <p>
453      * The set of global Java 3D properties always includes values for
454      * the following keys:
455      *
456      * <p>
457      * <ul>
458      * <table BORDER=1 CELLSPACING=1 CELLPADDING=1>
459      * <tr>
460      * <td><b>Key (String)</b></td>
461      * <td><b>Value Type</b></td>
462      * </tr>
463      * <tr>
464      * <td><code>j3d.version</code></td>
465      * <td>String</td>
466      * </tr>
467      * <tr>
468      * <td><code>j3d.vendor</code></td>
469      * <td>String</td>
470      * </tr>
471      * <tr>
472      * <td><code>j3d.specification.version</code></td>
473      * <td>String</td>
474      * </tr>
475      * <tr>
476      * <td><code>j3d.specification.vendor</code></td>
477      * <td>String</td>
478      * </tr>
479      * <tr>
480      * <td><code>j3d.pipeline</code></td>
481      * <td>String</td>
482      * </tr>
483      * <tr>
484      * <td><code>j3d.renderer</code></td>
485      * <td>String</td>
486      * </tr>
487      * </table>
488      * </ul>
489      *
490      * <p>
491      * The descriptions of the values returned for each key are as follows:
492      *
493      * <p>
494      * <ul>
495      *
496      * <li>
497      * <code>j3d.version</code>
498      * <ul>
499      * A String that defines the Java 3D implementation version.
500      * The portion of the implementation version string before the first
501      * space must adhere to one of the the following three formats
502      * (anything after the first space is an optional free-form addendum
503      * to the version):
504      * <ul>
505      * <i>x</i>.<i>y</i>.<i>z</i><br>
506      * <i>x</i>.<i>y</i>.<i>z</i>_<i>p</i><br>
507      * <i>x</i>.<i>y</i>.<i>z</i>-<i>ssss</i><br>
508      * </ul>
509      * where:
510      * <ul>
511      * <i>x</i> is the major version number<br>
512      * <i>y</i> is the minor version number<br>
513      * <i>z</i> is the sub-minor version number<br>
514      * <i>p</i> is the patch revision number <br>
515      * <i>ssss</i> is a string, identifying a non-release build
516      * (e.g., beta1, build47, rc1, etc.).  It may only
517      * contain letters, numbers, periods, dashes, or
518      * underscores.
519      * </ul>
520      * </ul>
521      * </li>
522      * <p>
523      *
524      * <li>
525      * <code>j3d.vendor</code>
526      * <ul>
527      * String that specifies the Java 3D implementation vendor.
528      * </ul>
529      * </li>
530      * <p>
531      *
532      * <li>
533      * <code>j3d.specification.version</code>
534      * <ul>
535      * A String that defines the Java 3D specification version.
536      * This string must be of the following form:
537      * <ul>
538      * <i>x</i>.<i>y</i>
539      * </ul>
540      * where:
541      * <ul>
542      * <i>x</i> is the major version number<br>
543      * <i>y</i> is the minor version number<br>
544      * </ul>
545      * No other characters are allowed in the specification version string.
546      * </ul>
547      * </li>
548      * <p>
549      *
550      * <li>
551      * <code>j3d.specification.vendor</code>
552      * <ul>
553      * String that specifies the Java 3D specification vendor.
554      * </ul>
555      * </li>
556      * <p>
557      *
558      * <li>
559      * <code>j3d.pipeline</code>
560      * <ul>
561      * String that specifies the Java 3D rendering pipeline. This could
562      * be one of: "NATIVE_OGL", "NATIVE_D3D", or "JOGL". Others could be
563      * added in the future.
564      * </ul>
565      * </li>
566      * <p>
567      *
568      * <li>
569      * <code>j3d.renderer</code>
570      * <ul>
571      * String that specifies the underlying rendering library.  This could
572      * be one of: "OpenGL" or "DirectX". Others could be added in the future.
573      * </ul>
574      * </li>
575      * <p>
576      *
577      * </ul>
578      *
579      * @return the global Java 3D properties
580      *
581      * @since Java 3D 1.3
582      */
getProperties()583     public static final Map getProperties() {
584 	if (properties == null) {
585 	    // Create lists of keys and values
586 	    ArrayList keys = new ArrayList();
587 	    ArrayList values = new ArrayList();
588 
589             // Implementation version string is obtained from the
590             // ImplementationVersion class.
591 	    keys.add("j3d.version");
592 	    values.add(VersionInfo.getVersion());
593 
594 	    keys.add("j3d.vendor");
595 	    values.add(VersionInfo.getVendor());
596 
597 	    keys.add("j3d.specification.version");
598 	    values.add(VersionInfo.getSpecificationVersion());
599 
600 	    keys.add("j3d.specification.vendor");
601 	    values.add(VersionInfo.getSpecificationVendor());
602 
603 	    keys.add("j3d.renderer");
604             values.add(Pipeline.getPipeline().getRendererName());
605 
606             keys.add("j3d.pipeline");
607             values.add(Pipeline.getPipeline().getPipelineName());
608 
609 	    // Now Create read-only properties object
610 	    properties =
611 		new J3dQueryProps((String[]) keys.toArray(new String[0]),
612 				  values.toArray());
613 	}
614   	return properties;
615     }
616 
617 
618     /**
619      * This returns the next available nodeId as a string.
620      */
621     // XXXX: reuse of id's imply a slight collision problem in the
622     // render queue's.
623     // BUG 4181362
getNodeId()624     String getNodeId() {
625         String str;
626 
627 	if (nodeIdFreeList.size() == 0) {
628 	   str = Long.toString(nodeIdCount);
629            nodeIdCount++;
630 	} else {
631             // Issue 496: Remove last object using index to avoid performance
632             // hit of a needless linear search.
633            int idx = nodeIdFreeList.size() - 1;
634            str = (String) nodeIdFreeList.remove(idx);
635 	}
636         return(str);
637     }
638 
639     /**
640      * This returns the next available viewId
641      */
getViewId()642     Integer getViewId() {
643 	Integer id;
644 	int size;
645 
646 	synchronized (viewIdFreeList) {
647 	    size = viewIdFreeList.size();
648 	    if (size == 0) {
649 		id = new Integer(viewIdCount++);
650 	    } else {
651 		id = (Integer) viewIdFreeList.remove(size-1);
652 	    }
653 	}
654         return(id);
655     }
656 
657     /**
658      * This returns a viewId to the freelist
659      */
addViewIdToFreeList(Integer viewId)660     void addViewIdToFreeList(Integer viewId) {
661 	synchronized (viewIdFreeList) {
662 	    viewIdFreeList.add(viewId);
663 	}
664     }
665 
addViewPlatform(ViewPlatformRetained vp)666     void addViewPlatform(ViewPlatformRetained vp) {
667 	vpChanged = true;
668 	viewPlatforms.add(vp);
669     }
670 
removeViewPlatform(ViewPlatformRetained vp)671     void removeViewPlatform(ViewPlatformRetained vp) {
672 	vpChanged = true;
673 	viewPlatforms.remove(viewPlatforms.indexOf(vp));
674     }
675 
getViewPlatformList()676     synchronized Object[] getViewPlatformList() {
677 	if (vpChanged) {
678 	    viewPlatformList = viewPlatforms.toArray();
679 	    vpChanged = false;
680 	}
681 	return viewPlatformList;
682     }
683 
checkForEnableEvents()684     void checkForEnableEvents() {
685 	enableComponentEvents();
686 	if (enableFocus) {
687 	    enableFocusEvents();
688 	}
689 	if (enableKey) {
690 	    enableKeyEvents();
691 	}
692 	if (enableMouse) {
693 	    enableMouseEvents();
694 	}
695 	if (enableMouseMotion) {
696 	    enableMouseMotionEvents();
697 	}
698 	if (enableMouseWheel) {
699 	    enableMouseWheelEvents();
700 	}
701 
702     }
703 
enableComponentEvents()704     void enableComponentEvents() {
705         // Issue 458 - This method is now a noop
706         /*
707 	Enumeration cvs;
708 	Canvas3D cv;
709         ViewPlatformRetained vp;
710 	View views[];
711 	Object[] vps = getViewPlatformList();
712 
713 	if (vps != null) {
714 	    for (int i=0; i<vps.length; i++) {
715                 vp =(ViewPlatformRetained)vps[i];
716 		views = vp.getViewList();
717 		for (int j=views.length-1; j>=0; j--) {
718 	            cvs = views[j].getAllCanvas3Ds();
719 	            while(cvs.hasMoreElements()) {
720 		        cv = (Canvas3D) cvs.nextElement();
721                         // offscreen canvas does not have event catcher
722                         if (cv.eventCatcher != null) {
723 		            cv.eventCatcher.enableComponentEvents();
724                         }
725 	            }
726 		}
727 	    }
728 	}
729         */
730     }
731 
disableFocusEvents()732     void disableFocusEvents() {
733 	Enumeration cvs;
734 	Canvas3D cv;
735         ViewPlatformRetained vp;
736 	View views[];
737 	Object[] vps = getViewPlatformList();
738 	enableFocus = false;
739 
740 	if (vps != null) {
741 	    for (int i=0; i<vps.length; i++) {
742                 vp =(ViewPlatformRetained)vps[i];
743 		views = vp.getViewList();
744 		for (int j=views.length-1; j>=0; j--) {
745                     cvs = views[j].getAllCanvas3Ds();
746 	            while(cvs.hasMoreElements()) {
747 		        cv = (Canvas3D) cvs.nextElement();
748                         // offscreen canvas does not have event catcher
749                         if (cv.eventCatcher != null)
750 		            cv.eventCatcher.disableFocusEvents();
751 	            }
752 	        }
753 	    }
754 	}
755 
756     }
757 
enableFocusEvents()758     void enableFocusEvents() {
759 	Enumeration cvs;
760 	Canvas3D cv;
761         ViewPlatformRetained vp;
762 	View views[];
763 	Object[] vps = getViewPlatformList();
764 	enableFocus = true;
765 
766 	if (vps != null) {
767 	    for (int i=0; i<vps.length; i++) {
768                 vp =(ViewPlatformRetained)vps[i];
769 		views = vp.getViewList();
770 		for (int j=views.length-1; j>=0; j--) {
771                     cvs = views[j].getAllCanvas3Ds();
772 	            while(cvs.hasMoreElements()) {
773 		        cv = (Canvas3D) cvs.nextElement();
774                         // offscreen canvas does not have event catcher
775                         if (cv.eventCatcher != null)
776 		            cv.eventCatcher.enableFocusEvents();
777 	            }
778 	        }
779 	    }
780 	}
781     }
782 
783 
disableKeyEvents()784     void disableKeyEvents() {
785 	Enumeration cvs;
786 	Canvas3D cv;
787         ViewPlatformRetained vp;
788 	Object[] vps = getViewPlatformList();
789 	View views[];
790 
791 	enableKey = false;
792 
793 	if (vps != null) {
794 	    for (int i=0; i<vps.length; i++) {
795                 vp =(ViewPlatformRetained)vps[i];
796 		views = vp.getViewList();
797 		for (int j=views.length-1; j>=0; j--) {
798                     cvs = views[j].getAllCanvas3Ds();
799 	            while(cvs.hasMoreElements()) {
800 		        cv = (Canvas3D) cvs.nextElement();
801                         // offscreen canvas does not have event catcher
802                         if (cv.eventCatcher != null)
803 			    cv.eventCatcher.disableKeyEvents();
804 	            }
805 	        }
806 	    }
807 	}
808     }
809 
810 
enableKeyEvents()811     void enableKeyEvents() {
812 	Enumeration cvs;
813 	Canvas3D cv;
814         ViewPlatformRetained vp;
815 	Object[] vps = getViewPlatformList();
816 	View views[];
817 
818 	enableKey = true;
819 
820 	if (vps != null) {
821 	    for (int i=0; i<vps.length; i++) {
822                 vp =(ViewPlatformRetained)vps[i];
823 		views = vp.getViewList();
824 		for (int j=views.length-1; j>=0; j--) {
825                     cvs = views[j].getAllCanvas3Ds();
826 	            while(cvs.hasMoreElements()) {
827 		        cv = (Canvas3D) cvs.nextElement();
828                         // offscreen canvas does not have event catcher
829                         if (cv.eventCatcher != null)
830 			    cv.eventCatcher.enableKeyEvents();
831 	            }
832 	        }
833 	    }
834 	}
835     }
836 
837 
disableMouseEvents()838    void disableMouseEvents() {
839 	Enumeration cvs;
840 	Canvas3D cv;
841 	View views[];
842         ViewPlatformRetained vp;
843 	Object[] vps = getViewPlatformList();
844 
845 	enableMouse = false;
846 
847 	if (vps != null) {
848 	    for (int i=0; i<vps.length; i++) {
849                 vp =(ViewPlatformRetained)vps[i];
850 		views = vp.getViewList();
851 		for (int j=views.length-1; j>=0; j--) {
852                     cvs = views[j].getAllCanvas3Ds();
853 	            while(cvs.hasMoreElements()) {
854 		        cv = (Canvas3D) cvs.nextElement();
855                         // offscreen canvas does not have event catcher
856                         if (cv.eventCatcher != null)
857 		            cv.eventCatcher.disableMouseEvents();
858 	            }
859 	        }
860 	    }
861 	}
862     }
863 
enableMouseEvents()864     void enableMouseEvents() {
865 	Enumeration cvs;
866 	Canvas3D cv;
867 	View views[];
868         ViewPlatformRetained vp;
869 	Object[] vps = getViewPlatformList();
870 
871 	enableMouse = true;
872 
873 	if (vps != null) {
874 	    for (int i=0; i<vps.length; i++) {
875                 vp =(ViewPlatformRetained)vps[i];
876 		views = vp.getViewList();
877 		for (int j=views.length-1; j>=0; j--) {
878                     cvs = views[j].getAllCanvas3Ds();
879 	            while(cvs.hasMoreElements()) {
880 		        cv = (Canvas3D) cvs.nextElement();
881                         // offscreen canvas does not have event catcher
882                         if (cv.eventCatcher != null)
883 		            cv.eventCatcher.enableMouseEvents();
884 	            }
885 	        }
886 	    }
887 	}
888     }
889 
890 
disableMouseMotionEvents()891     void disableMouseMotionEvents() {
892 	Enumeration cvs;
893 	Canvas3D cv;
894 	View views[];
895         ViewPlatformRetained vp;
896 	Object[] vps = getViewPlatformList();
897 
898 	enableMouseMotion = false;
899 
900 	if (vps != null) {
901 	    for (int i=0; i<vps.length; i++) {
902                 vp =(ViewPlatformRetained)vps[i];
903 		views = vp.getViewList();
904 		for (int j=views.length-1; j>=0; j--) {
905                     cvs = views[j].getAllCanvas3Ds();
906 	            while(cvs.hasMoreElements()) {
907 		        cv = (Canvas3D) cvs.nextElement();
908                         // offscreen canvas does not have event catcher
909                         if (cv.eventCatcher != null)
910 		            cv.eventCatcher.disableMouseMotionEvents();
911 	            }
912 	        }
913 	    }
914 	}
915     }
916 
enableMouseMotionEvents()917     void enableMouseMotionEvents() {
918 	Enumeration cvs;
919 	Canvas3D cv;
920 	View views[];
921         ViewPlatformRetained vp;
922 	Object[] vps = getViewPlatformList();
923 
924 	enableMouseMotion = true;
925 
926 	if (vps != null) {
927 	    for (int i=0; i<vps.length; i++) {
928                 vp =(ViewPlatformRetained)vps[i];
929 		views = vp.getViewList();
930 		for (int j=views.length-1; j>=0; j--) {
931                     cvs = views[j].getAllCanvas3Ds();
932 	            while(cvs.hasMoreElements()) {
933 		        cv = (Canvas3D) cvs.nextElement();
934                         // offscreen canvas does not have event catcher
935                         if (cv.eventCatcher != null)
936 		            cv.eventCatcher.enableMouseMotionEvents();
937 	            }
938 	        }
939 	    }
940 	}
941     }
942 
disableMouseWheelEvents()943     void disableMouseWheelEvents() {
944 	Enumeration cvs;
945 	Canvas3D cv;
946 	View views[];
947         ViewPlatformRetained vp;
948 	Object[] vps = getViewPlatformList();
949 
950 	enableMouseWheel = false;
951 
952 	if (vps != null) {
953 	    for (int i=0; i<vps.length; i++) {
954                 vp =(ViewPlatformRetained)vps[i];
955 		views = vp.getViewList();
956 		for (int j=views.length-1; j>=0; j--) {
957                     cvs = views[j].getAllCanvas3Ds();
958 	            while(cvs.hasMoreElements()) {
959 		        cv = (Canvas3D) cvs.nextElement();
960                         // offscreen canvas does not have event catcher
961                         if (cv.eventCatcher != null)
962 		            cv.eventCatcher.disableMouseWheelEvents();
963 	            }
964 	        }
965 	    }
966 	}
967     }
968 
enableMouseWheelEvents()969     void enableMouseWheelEvents() {
970 	Enumeration cvs;
971 	Canvas3D cv;
972 	View views[];
973         ViewPlatformRetained vp;
974 	Object[] vps = getViewPlatformList();
975 
976 	enableMouseWheel = true;
977 
978 	if (vps != null) {
979 	    for (int i=0; i<vps.length; i++) {
980                 vp =(ViewPlatformRetained)vps[i];
981 		views = vp.getViewList();
982 		for (int j=views.length-1; j>=0; j--) {
983                     cvs = views[j].getAllCanvas3Ds();
984 	            while(cvs.hasMoreElements()) {
985 		        cv = (Canvas3D) cvs.nextElement();
986                         // offscreen canvas does not have event catcher
987                         if (cv.eventCatcher != null)
988 		            cv.eventCatcher.enableMouseWheelEvents();
989 	            }
990 	        }
991 	    }
992 	}
993     }
994 
995     /**
996      * Sets the "current" view (during view activation) for this virtual
997      * universe.
998      * @param last activated view
999      */
setCurrentView(View view)1000     final void setCurrentView(View view) {
1001         this.currentView = view;
1002     }
1003 
1004     /**
1005      * Returns the "current" view (the last view activated for this virtual
1006      * universe.
1007      * @return last activated view
1008      */
getCurrentView()1009     final View getCurrentView() {
1010         return this.currentView;
1011     }
1012 
1013 
1014     /**
1015      * Method to return the root thread group.  This must be called from
1016      * within a doPrivileged block.
1017      */
getRootThreadGroup()1018     static ThreadGroup getRootThreadGroup() {
1019 	return rootThreadGroup;
1020     }
1021 
1022     /**
1023      * return true if all Locales under it don't have branchGroup
1024      * attach to it.
1025      */
isEmpty()1026     boolean isEmpty() {
1027 	Enumeration elm = listOfLocales.elements();
1028 
1029 	while (elm.hasMoreElements()) {
1030 	    Locale loc = (Locale) elm.nextElement();
1031 	    if (!loc.branchGroups.isEmpty()) {
1032 		return false;
1033 	    }
1034 	}
1035 	return true;
1036     }
1037 
resetWaitMCFlag()1038     void resetWaitMCFlag() {
1039 	synchronized (waitLock) {
1040 	    regViewWaiting = null;
1041 	    unRegViewWaiting = null;
1042 	    isSceneGraphLock = true;
1043 	}
1044     }
1045 
waitForMC()1046     void waitForMC() {
1047 	synchronized (waitLock) {
1048 	    if (unRegViewWaiting != null) {
1049 		if ((regViewWaiting == null) ||
1050 		    (regViewWaiting != unRegViewWaiting)) {
1051 		    while (!unRegViewWaiting.doneUnregister) {
1052 		        MasterControl.threadYield();
1053 		    }
1054 		    unRegViewWaiting.doneUnregister = false;
1055 		    unRegViewWaiting = null;
1056 		}
1057 	    }
1058 
1059 	    if (regViewWaiting != null) {
1060 		while (!VirtualUniverse.mc.isRegistered(regViewWaiting)) {
1061 		    MasterControl.threadYield();
1062 		}
1063 		regViewWaiting = null;
1064 	    }
1065 	    isSceneGraphLock = false;
1066 	}
1067     }
1068 
1069     /**
1070      * Adds the specified GraphStructureChangeListener to the set of listeners
1071      * that will be notified when the graph structure is changed on a live
1072      * scene graph. If the specifed listener is null no action is taken and no
1073      * exception is thrown.
1074      *
1075      * @param listener the listener to add to the set.
1076      *
1077      * @since Java 3D 1.4
1078      */
addGraphStructureChangeListener(GraphStructureChangeListener listener)1079     public void addGraphStructureChangeListener(GraphStructureChangeListener listener) {
1080         if (listener == null) {
1081             return;
1082         }
1083 
1084         if (structureChangeListenerSet == null) {
1085             structureChangeListenerSet = new HashSet();
1086         }
1087 
1088         synchronized(structureChangeListenerSet) {
1089             structureChangeListenerSet.add(listener);
1090         }
1091     }
1092 
1093     /**
1094      * Removes the specified GraphStructureChangeListener from the set of listeners. This
1095      * method performs no function, nor does it throw an exception if the specified listener
1096      * is not currently in the set or is null.
1097      *
1098      * @param listener the listener to remove from the set.
1099      *
1100      * @since Java 3D 1.4
1101      */
removeGraphStructureChangeListener(GraphStructureChangeListener listener)1102     public void removeGraphStructureChangeListener(GraphStructureChangeListener listener) {
1103         if (structureChangeListenerSet == null) {
1104 	    return;
1105 	}
1106 
1107         synchronized(structureChangeListenerSet) {
1108             structureChangeListenerSet.remove(listener);
1109         }
1110     }
1111 
1112     /**
1113      * Processes all live BranchGroup add and removes and notifies
1114      * any registered listeners. Used for add and remove
1115      */
notifyStructureChangeListeners(boolean add, Object parent, BranchGroup child)1116     void notifyStructureChangeListeners(boolean add, Object parent, BranchGroup child) {
1117         if (structureChangeListenerSet == null) {
1118             return;
1119 	}
1120 
1121         synchronized(structureChangeListenerSet) {
1122             Iterator<GraphStructureChangeListener> it = structureChangeListenerSet.iterator();
1123             while(it.hasNext()) {
1124                 GraphStructureChangeListener listener = it.next();
1125                 try {
1126                     if (add) {
1127                         listener.branchGroupAdded(parent, child);
1128                     } else {
1129                         listener.branchGroupRemoved(parent, child);
1130                     }
1131                 }
1132                 catch (RuntimeException e) {
1133                     System.err.println("Exception occurred in GraphStructureChangeListener:");
1134                     e.printStackTrace();
1135                 }
1136                 catch (Error e) {
1137                     // Issue 264 - catch Error
1138                     System.err.println("Error occurred in GraphStructureChangeListener:");
1139                     e.printStackTrace();
1140                 }
1141             }
1142         }
1143     }
1144 
1145     /**
1146      * Processes all live BranchGroup moves and notifies
1147      * any registered listeners. Used for moveTo
1148      */
notifyStructureChangeListeners(Object oldParent, Object newParent, BranchGroup child)1149     void notifyStructureChangeListeners(Object oldParent, Object newParent, BranchGroup child) {
1150         if (structureChangeListenerSet == null) {
1151             return;
1152 	}
1153 
1154         synchronized(structureChangeListenerSet) {
1155             Iterator<GraphStructureChangeListener> it = structureChangeListenerSet.iterator();
1156             while(it.hasNext()) {
1157                 GraphStructureChangeListener listener = it.next();
1158                 try {
1159                     listener.branchGroupMoved(oldParent, newParent, child);
1160                 }
1161                 catch (RuntimeException e) {
1162                     System.err.println("Exception occurred in GraphStructureChangeListener:");
1163                     e.printStackTrace();
1164                 }
1165                 catch (Error e) {
1166                     // Issue 264 - catch Error
1167                     System.err.println("Error occurred in GraphStructureChangeListener:");
1168                     e.printStackTrace();
1169                 }
1170             }
1171         }
1172     }
1173 
1174 
1175     /**
1176      * Adds the specified ShaderErrorListener to the set of listeners
1177      * that will be notified when a programmable shader error is
1178      * detected on a live scene graph. If the specifed listener is
1179      * null no action is taken and no exception is thrown.
1180      * If a shader error occurs, the listeners will be called
1181      * asynchronously from a separate notification thread. The Java 3D
1182      * renderer and behavior scheduler will continue to run as if the
1183      * error had not occurred, except that shading will be disabled
1184      * for the objects in error. If applications desire to detach or
1185      * modify the scene graph as a result of the error, they should
1186      * use a behavior post if they want that change to be
1187      * synchronous with the renderer.
1188      *
1189      * @param listener the listener to add to the set.
1190      *
1191      * @since Java 3D 1.4
1192      */
addShaderErrorListener(ShaderErrorListener listener)1193     public void addShaderErrorListener(ShaderErrorListener listener) {
1194         if (listener == null) {
1195             return;
1196         }
1197 
1198         if (shaderErrorListenerSet == null) {
1199             shaderErrorListenerSet = new HashSet();
1200         }
1201 
1202         synchronized(shaderErrorListenerSet) {
1203             shaderErrorListenerSet.add(listener);
1204         }
1205     }
1206 
1207     /**
1208      * Removes the specified ShaderErrorListener from the set of
1209      * listeners. This method performs no function, nor does it throw
1210      * an exception if the specified listener is not currently in the
1211      * set or is null.
1212      *
1213      * @param listener the listener to remove from the set.
1214      *
1215      * @since Java 3D 1.4
1216      */
removeShaderErrorListener(ShaderErrorListener listener)1217     public void removeShaderErrorListener(ShaderErrorListener listener) {
1218         if (shaderErrorListenerSet == null) {
1219 	    return;
1220 	}
1221 
1222         synchronized(shaderErrorListenerSet) {
1223             shaderErrorListenerSet.remove(listener);
1224         }
1225     }
1226 
1227     /**
1228      * Notifies all listeners of a shader error. If no listeners exist, a default
1229      * listener is notified.
1230      */
notifyShaderErrorListeners(ShaderError error)1231     void notifyShaderErrorListeners(ShaderError error) {
1232 	boolean errorReported = false;
1233 
1234 	// Notify all error listeners in the set
1235         if (shaderErrorListenerSet != null) {
1236             synchronized(shaderErrorListenerSet) {
1237                 Iterator<ShaderErrorListener> it = shaderErrorListenerSet.iterator();
1238                 while(it.hasNext()) {
1239                     ShaderErrorListener listener = it.next();
1240                     try {
1241                         listener.errorOccurred(error);
1242                     }
1243                     catch (RuntimeException e) {
1244                         System.err.println("Exception occurred in ShaderErrorListener:");
1245                         e.printStackTrace();
1246                     }
1247                     catch (Error e) {
1248                         // Issue 264 - catch Error
1249                         System.err.println("Error occurred in ShaderErrorListener:");
1250                         e.printStackTrace();
1251                     }
1252                     errorReported = true;
1253                 }
1254             }
1255         }
1256 
1257         // Notify the default error listener if the set is null or empty
1258         if (!errorReported) {
1259             defaultShaderErrorListener.errorOccurred(error);
1260         }
1261     }
1262 
1263 
1264     // Issue 260 : rendering error listeners.
1265 
1266     /**
1267      * Adds the specified RenderingErrorListener to the set of listeners
1268      * that will be notified when a rendering error is detected.
1269      * If the specifed listener is null no action is taken and no exception
1270      * is thrown.
1271      * If a rendering error occurs, the listeners will be called
1272      * asynchronously from a separate notification thread.  If the set
1273      * of listeners is empty, a default listener is notified. The
1274      * default listener prints the error information to System.err and
1275      * then calls System.exit().
1276      *
1277      * @param listener the listener to add to the set.
1278      *
1279      * @since Java 3D 1.5
1280      */
addRenderingErrorListener(RenderingErrorListener listener)1281     public static void addRenderingErrorListener(RenderingErrorListener listener) {
1282         if (listener == null) {
1283             return;
1284         }
1285 
1286         if (renderingErrorListenerSet == null) {
1287             renderingErrorListenerSet = new HashSet();
1288         }
1289 
1290         synchronized(renderingErrorListenerSet) {
1291             renderingErrorListenerSet.add(listener);
1292         }
1293     }
1294 
1295     /**
1296      * Removes the specified RenderingErrorListener from the set of
1297      * listeners. This method performs no function, nor does it throw
1298      * an exception if the specified listener is not currently in the
1299      * set or is null.
1300      *
1301      * @param listener the listener to remove from the set.
1302      *
1303      * @since Java 3D 1.5
1304      */
removeRenderingErrorListener(RenderingErrorListener listener)1305     public static void removeRenderingErrorListener(RenderingErrorListener listener) {
1306         if (renderingErrorListenerSet == null) {
1307 	    return;
1308 	}
1309 
1310         synchronized(renderingErrorListenerSet) {
1311             renderingErrorListenerSet.remove(listener);
1312         }
1313     }
1314 
1315     /**
1316      * Notifies all listeners of a rendering error. If no listeners exist,
1317      * a default listener is notified.
1318      */
notifyRenderingErrorListeners(RenderingError error)1319     static void notifyRenderingErrorListeners(RenderingError error) {
1320 	boolean errorReported = false;
1321 
1322 	// Notify all error listeners in the set
1323         if (renderingErrorListenerSet != null) {
1324             synchronized(renderingErrorListenerSet) {
1325                 Iterator<RenderingErrorListener> it = renderingErrorListenerSet.iterator();
1326                 while(it.hasNext()) {
1327                     RenderingErrorListener listener = it.next();
1328                     try {
1329                         listener.errorOccurred(error);
1330                     }
1331                     catch (RuntimeException e) {
1332                         System.err.println("Exception occurred in RenderingErrorListener:");
1333                         e.printStackTrace();
1334                     }
1335                     catch (Error e) {
1336                         // Issue 264 - catch Error
1337                         System.err.println("Error occurred in RenderingErrorListener:");
1338                         e.printStackTrace();
1339                     }
1340                     errorReported = true;
1341                 }
1342             }
1343         }
1344 
1345         // Notify the default error listener if the set is null or empty
1346         if (!errorReported) {
1347             defaultRenderingErrorListener.errorOccurred(error);
1348         }
1349     }
1350 
1351 }
1352