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