/*
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package javax.media.j3d;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A VirtualUniverse object is the top-level container for all scene
* graphs. A virtual universe consists of a set of Locale objects,
* each of which has a high-resolution position within the virtual
* universe. An application or applet may have more than one
* VirtualUniverse objects, but many applications will need only one.
* Virtual universes are separate entities in that no node object may
* exist in more than one virtual universe at any one time. Likewise,
* the objects in one virtual universe are not visible in, nor do they
* interact with objects in, any other virtual universe.
*
* A VirtualUniverse object defines methods to enumerate its Locale
* objects and to remove them from the virtual universe.
*
*
* For more information, see the
* Introduction to the Java 3D API and
* Scene Graph Superstructure
* documents.
*
* @see Locale
*/
public class VirtualUniverse extends Object {
// NOTE TO DEVELOPERS:
//
// Developers who modify Java 3D in any way should modify
// the auxiliary implementation vendor string in VersionInfo.java.
// See that file for instructions.
// The global MasterControl object. There is only one of these
// for all of Java 3D.
static MasterControl mc = null;
// The lock to acquire before traversing the scene graph
Object sceneGraphLock = new Object();
Object behaviorLock = new Object();
// A list of locales that are contained within this universe
Vector listOfLocales = new Vector();
// The list of view platforms, a changed flag and a cached array
private ArrayList viewPlatforms = new ArrayList();
private boolean vpChanged = false;
private ViewPlatformRetained[] viewPlatformList = new ViewPlatformRetained[0];
// The Behavior Scheduler Thread for this Virtual Universe.
BehaviorScheduler behaviorScheduler = null;
// The geometry structure for this Universe
GeometryStructure geometryStructure = null;
// The transform structure for this Universe
TransformStructure transformStructure = null;
// The behavior structure for this Universe
BehaviorStructure behaviorStructure = null;
// The sound structure for this Universe
SoundStructure soundStructure = null;
// The rendering attributes structure for this Universe
RenderingEnvironmentStructure renderingEnvironmentStructure = null;
// Reference count of users of the RenderingEnvironmentStructure
int renderingEnvironmentStructureRefCount = 0;
// This is a global counter for node id's.
long nodeIdCount = 0;
// This is a global counter for view id's.
int viewIdCount = 0;
// This is a vector of free nodeid's
Vector nodeIdFreeList = new Vector();
// This is a vector of free viewid's
ArrayList viewIdFreeList = new ArrayList();
// The number of nodes in this universe
int numNodes = 0;
// The State object used when branch graphs are added
SetLiveState setLiveState;
// This is an array of references to objects that need their mirror
// copies updated. It is updated by the traverser and emptied by
// the view thread.
ObjectUpdate[] updateObjects = new ObjectUpdate[16];
// The number of valid entries in updateObjects
int updateObjectsLen = 0;
// The current primary view for this universe
View currentView;
// A flag to indicate that we are in a behavior routine
boolean inBehavior = false;
// Flags to indicate if events need to be delivered
boolean enableComponent = false;
boolean enableFocus = false;
boolean enableKey = false;
boolean enableMouse = false;
boolean enableMouseMotion = false;
boolean enableMouseWheel = false;
// Keep track of how many active View use this universe
int activeViewCount = 0;
// Root ThreadGroup for creating Java 3D threads
static ThreadGroup rootThreadGroup;
// Properties object for getProperties
private static J3dQueryProps properties = null;
// Flag to indicate that user thread has to
// stop until MC completely register/unregister View.
View regViewWaiting = null;
View unRegViewWaiting = null;
boolean isSceneGraphLock = false;
private Object waitLock = new Object();
// Set of scene graph structure change listeners
private HashSet structureChangeListenerSet = null;
// Set of shader error listeners
private HashSet shaderErrorListenerSet = null;
private ShaderErrorListener defaultShaderErrorListener =
ShaderProgram.getDefaultErrorListener();
// Set of rendering error listeners
private static HashSet renderingErrorListenerSet = null;
private static RenderingErrorListener defaultRenderingErrorListener =
Renderer.getDefaultErrorListener();
/**
* Constructs a new VirtualUniverse.
*/
public VirtualUniverse() {
setLiveState = new SetLiveState(this);
initMCStructure();
}
void initMCStructure() {
if (geometryStructure != null) {
geometryStructure.cleanup();
}
geometryStructure = new GeometryStructure(this);
if (transformStructure != null) {
transformStructure.cleanup();
}
transformStructure = new TransformStructure(this);
if (behaviorStructure != null) {
behaviorStructure.cleanup();
}
behaviorStructure = new BehaviorStructure(this);
if (soundStructure != null) {
soundStructure.cleanup();
}
soundStructure = new SoundStructure(this);
if (renderingEnvironmentStructure != null) {
renderingEnvironmentStructure.cleanup();
}
renderingEnvironmentStructure = new
RenderingEnvironmentStructure(this);
}
/**
* Initialize the native interface and anything else that needs
* to be initialized.
*/
static void loadLibraries() {
// No need to do anything. The act of calling any method in this
// class is sufficient to cause the static MasterControl object
// to be created which, in turn, loads the native libraries.
}
static {
boolean isLoggableConfig = MasterControl.isCoreLoggable(Level.CONFIG);
Logger logger = MasterControl.getCoreLogger();
// Print out version information unless this is a
// non-debuggable, release (fcs) build
if (isLoggableConfig || J3dDebug.devPhase || VersionInfo.isDebug) {
StringBuffer strBuf = new StringBuffer("3D ");
if (J3dDebug.devPhase) {
strBuf.append("[dev] ");
}
strBuf.append(VersionInfo.getVersion());
String str = strBuf.toString();
if (isLoggableConfig) {
logger.config(str);
} else {
System.err.println(str);
System.err.println();
}
}
// Print out debugging information for debug builds
if (isLoggableConfig || VersionInfo.isDebug) {
StringBuffer strBuf = new StringBuffer();
strBuf.append("Initializing 3D runtime system:\n").
append(" version = ").
append(VersionInfo.getVersion()).
append("\n").
append(" vendor = ").
append(VersionInfo.getVendor()).
append("\n").
append(" specification.version = ").
append(VersionInfo.getSpecificationVersion()).
append("\n").
append(" specification.vendor = ").
append(VersionInfo.getSpecificationVendor());
String str = strBuf.toString();
if (isLoggableConfig) {
logger.config(str);
} else {
System.err.println(str);
System.err.println();
}
}
// Load the native libraries and create the static
// MasterControl object
MasterControl.loadLibraries();
mc = new MasterControl();
// Print out debugging information for debug builds
if (isLoggableConfig || VersionInfo.isDebug) {
StringBuffer strBuf = new StringBuffer();
strBuf.append("3D system initialized\n").
append(" rendering pipeline = ").
append(Pipeline.getPipeline().getPipelineName());
String str = strBuf.toString();
if (isLoggableConfig) {
logger.config(str);
} else {
System.err.println(str);
System.err.println();
}
}
}
/**
* Adds a locale at the end of list of locales
* @param locale the locale to be added
*/
void addLocale(Locale locale) {
listOfLocales.addElement(locale);
}
/**
* Removes a Locale and its associates branch graphs from this
* universe. All branch graphs within the specified Locale are
* detached, regardless of whether their ALLOW_DETACH capability
* bits are set. The Locale is then marked as being dead: no
* branch graphs may subsequently be attached.
*
* @param locale the Locale to be removed.
*
* @exception IllegalArgumentException if the specified Locale is not
* attached to this VirtualUniverse.
*
* @since Java 3D 1.2
*/
public void removeLocale(Locale locale) {
if (locale.getVirtualUniverse() != this) {
throw new IllegalArgumentException(J3dI18N.getString("VirtualUniverse0"));
}
listOfLocales.removeElement(locale);
locale.removeFromUniverse();
if (isEmpty()) {
VirtualUniverse.mc.postRequest(MasterControl.EMPTY_UNIVERSE,
this);
}
setLiveState.reset(null);
}
/**
* Removes all Locales and their associates branch graphs from
* this universe. All branch graphs within each Locale are
* detached, regardless of whether their ALLOW_DETACH capability
* bits are set. Each Locale is then marked as being dead: no
* branch graphs may subsequently be attached. This method
* should be called by applications and applets to allow
* Java 3D to cleanup its resources.
*
* @since Java 3D 1.2
*/
public void removeAllLocales() {
// NOTE: this is safe because Locale.removeFromUniverse does not
// remove the Locale from the listOfLocales
int i;
for (i = listOfLocales.size() - 1; i > 0; i--) {
listOfLocales.get(i).removeFromUniverse();
}
if (i >= 0) {
// We have to clear() the listOfLocales first before
// invoke the last removeFromUniverse() so that isEmpty()
// (call from View.deactivate() ) will return true and
// threads can destroy from MC.
Locale loc = listOfLocales.get(0);
listOfLocales.clear();
loc.removeFromUniverse();
}
VirtualUniverse.mc.postRequest(MasterControl.EMPTY_UNIVERSE,
this);
setLiveState.reset(null);
}
/**
* Returns the enumeration object of all locales in this virtual universe.
*
* @return the enumeration object
*/
public Enumeration getAllLocales() {
return this.listOfLocales.elements();
}
/**
* Returns the number of locales.
* @return the count of locales
*/
public int numLocales() {
return this.listOfLocales.size();
}
/**
* Sets the priority of all Java 3D threads to the specified
* value. The default value is the priority of the thread that
* started Java 3D.
*
* @param priority the new thread priority
*
* @exception IllegalArgumentException if the priority is not in
* the range MIN_PRIORITY to MAX_PRIORITY
*
* @exception SecurityException if the priority is greater than
* that of the calling thread
*
* @since Java 3D 1.2
*/
public static void setJ3DThreadPriority(int priority) {
if (priority > Thread.MAX_PRIORITY) {
priority = Thread.MAX_PRIORITY;
} else if (priority < Thread.MIN_PRIORITY) {
priority = Thread.MIN_PRIORITY;
}
VirtualUniverse.mc.setThreadPriority(priority);
}
/**
* Retrieves that priority of Java 3D's threads.
*
* @return the current priority of Java 3D's threads
*
* @since Java 3D 1.2
*/
public static int getJ3DThreadPriority() {
return VirtualUniverse.mc.getThreadPriority();
}
/**
* Returns a read-only Map object containing key-value pairs that
* define various global properties for Java 3D. All of the keys
* are String objects. The values are key-specific, but most will
* be String objects.
*
*
* The set of global Java 3D properties always includes values for
* the following keys:
*
*
*
*
*
*
Key (String)
*
Value Type
*
*
*
j3d.version
*
String
*
*
*
j3d.vendor
*
String
*
*
*
j3d.specification.version
*
String
*
*
*
j3d.specification.vendor
*
String
*
*
*
j3d.pipeline
*
String
*
*
*
j3d.renderer
*
String
*
*
*
*
*
* The descriptions of the values returned for each key are as follows:
*
*
*
*
*
* j3d.version
*
* A String that defines the Java 3D implementation version.
* The portion of the implementation version string before the first
* space must adhere to one of the the following three formats
* (anything after the first space is an optional free-form addendum
* to the version):
*
* x.y.z
* x.y.z_p
* x.y.z-ssss
*
* where:
*
* x is the major version number
* y is the minor version number
* z is the sub-minor version number
* p is the patch revision number
* ssss is a string, identifying a non-release build
* (e.g., beta1, build47, rc1, etc.). It may only
* contain letters, numbers, periods, dashes, or
* underscores.
*
*
*
*
*
*
* j3d.vendor
*
* String that specifies the Java 3D implementation vendor.
*
*
*
*
*
* j3d.specification.version
*
* A String that defines the Java 3D specification version.
* This string must be of the following form:
*
* x.y
*
* where:
*
* x is the major version number
* y is the minor version number
*
* No other characters are allowed in the specification version string.
*
*
*
*
*
* j3d.specification.vendor
*
* String that specifies the Java 3D specification vendor.
*
*
*
*
*
* j3d.pipeline
*
* String that specifies the Java 3D rendering pipeline. This could
* be one of: "NATIVE_OGL", "NATIVE_D3D", or "JOGL". Others could be
* added in the future.
*
*
*
*
*
* j3d.renderer
*
* String that specifies the underlying rendering library. This could
* be one of: "OpenGL" or "DirectX". Others could be added in the future.
*
*
*
*
*
*
* @return the global Java 3D properties
*
* @since Java 3D 1.3
*/
public static final Map getProperties() {
if (properties == null) {
// Create lists of keys and values
ArrayList keys = new ArrayList();
ArrayList