/* * Copyright 1996-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 javax.vecmath.Color3f; /** * The Background leaf node defines a solid background color * and a background image that are used to fill the window at the * beginning of each new frame. The background image may be null. * It optionally allows background * geometry---which is pre-tessellated onto a unit sphere and is drawn * at infinity---to be referenced. It also specifies an application * region in which this background is active. A Background node is * active when its application region intersects the ViewPlatform's * activation volume. If multiple Background nodes are active, the * Background node that is "closest" to the eye will be used. If no * Background nodes are active, then the window is cleared to black. * *
* The set of nodes that can be added to a BranchGroup associated with * a Background node is limited. All Group nodes except * ViewSpecificGroup are legal in a background geometry branch * graph. The only Leaf nodes that are legal are Shape3D (except * OrientedShape3D), Morph, Light, and Fog. The presence of any other * Leaf node, including OrientedShape3D, or of a ViewSpecificGroup * node will cause an IllegalSceneGraphException to be thrown. Note * that Link nodes are not allowed; a background geometry branch graph * must not reference shared subgraphs. NodeComponent objects can be * shared between background branches and ordinary (non-background) * branches or among different background branches, however. * *
* Light and Fog nodes in a background geometry branch graph do not * affect nodes outside of the background geometry branch graph, and * vice versa. Light and Fog nodes that appear in a background * geometry branch graph must not be hierarchically scoped to any * group node outside of that background geometry branch graph. * Conversely, Light and Fog nodes that appear outside of a particular * background geometry branch graph must not be hierarchically scoped * to any group node in that background geometry branch graph. Any * attempt to do so will be ignored. * *
* The influencing bounds of any Light or Fog node in a background * geometry branch graph is effectively infinite (meaning that all * lights can affect all geometry objects nodes within the background * geometry graph, and that an arbitrary fog is selected). An * application wishing to limit the scope of a Light or Fog node must * use hierarchical scoping. * *
* Picking and collision is ignored for nodes inside a background
* geometry branch graph.
*/
public class Background extends Leaf {
/**
* Specifies that the Background allows read access to its application
* bounds and bounding leaf at runtime.
*/
public static final int
ALLOW_APPLICATION_BOUNDS_READ = CapabilityBits.BACKGROUND_ALLOW_APPLICATION_BOUNDS_READ;
/**
* Specifies that the Background allows write access to its application
* bounds and bounding leaf at runtime.
*/
public static final int
ALLOW_APPLICATION_BOUNDS_WRITE = CapabilityBits.BACKGROUND_ALLOW_APPLICATION_BOUNDS_WRITE;
/**
* Specifies that the Background allows read access to its image
* at runtime.
*/
public static final int
ALLOW_IMAGE_READ = CapabilityBits.BACKGROUND_ALLOW_IMAGE_READ;
/**
* Specifies that the Background allows write access to its image
* at runtime.
*/
public static final int
ALLOW_IMAGE_WRITE = CapabilityBits.BACKGROUND_ALLOW_IMAGE_WRITE;
/**
* Specifies that the Background allows read access to its color
* at runtime.
*/
public static final int
ALLOW_COLOR_READ = CapabilityBits.BACKGROUND_ALLOW_COLOR_READ;
/**
* Specifies that the Background allows write access to its color
* at runtime.
*/
public static final int
ALLOW_COLOR_WRITE = CapabilityBits.BACKGROUND_ALLOW_COLOR_WRITE;
/**
* Specifies that the Background allows read access to its
* background geometry at runtime.
*/
public static final int
ALLOW_GEOMETRY_READ = CapabilityBits.BACKGROUND_ALLOW_GEOMETRY_READ;
/**
* Specifies that the Background allows write access to its
* background geometry at runtime.
*/
public static final int
ALLOW_GEOMETRY_WRITE = CapabilityBits.BACKGROUND_ALLOW_GEOMETRY_WRITE;
/**
* Specifies that the Background allows read access to its image
* scale mode at runtime.
*
* @since Java 3D 1.3
*/
public static final int ALLOW_IMAGE_SCALE_MODE_READ =
CapabilityBits.BACKGROUND_ALLOW_IMAGE_SCALE_MODE_READ;
/**
* Specifies that the Background allows write access to its image
* scale mode at runtime.
*
* @since Java 3D 1.3
*/
public static final int ALLOW_IMAGE_SCALE_MODE_WRITE =
CapabilityBits.BACKGROUND_ALLOW_IMAGE_SCALE_MODE_WRITE;
/**
* Indicates that no scaling of the background image is done. The
* image will be drawn in its actual size. If the window is
* smaller than the image, the image will be clipped. If the
* window is larger than the image, the portion of the window not
* filled by the image will be filled with the background color.
* In all cases, the upper left corner of the image is anchored at
* the upper-left corner of the window.
* This is the default mode.
*
* @see #setImageScaleMode
*
* @since Java 3D 1.3
*/
public static final int SCALE_NONE = 0;
/**
* Indicates that the background image is uniformly scaled to fit
* the window such that the entire image is visible. The image is
* scaled by the smaller of window.width/image.width
* and window.height/image.height
. The image will
* exactly fill either the width or height of the window, but not
* necessarily both. The portion of the window not filled by the
* image will be filled with the background color.
* The upper left corner of the image is anchored at the
* upper-left corner of the window.
*
* @see #setImageScaleMode
*
* @since Java 3D 1.3
*/
public static final int SCALE_FIT_MIN = 1;
/**
* Indicates that the background image is uniformly scaled to fit
* the window such that the entire window is filled. The image is
* scaled by the larger of window.width/image.width
* and window.height/image.height
. The image will
* entirely fill the window, but may by clipped either in X
* or Y.
* The upper left corner of the image is anchored at the
* upper-left corner of the window.
*
* @see #setImageScaleMode
*
* @since Java 3D 1.3
*/
public static final int SCALE_FIT_MAX = 2;
/**
* Indicates that the background image is scaled to fit the
* window. The image is scaled non-uniformly in x and
* y by window.width/image.width
and and
* window.height/image.height
, respectively. The
* image will entirely fill the window.
*
* @see #setImageScaleMode
*
* @since Java 3D 1.3
*/
public static final int SCALE_FIT_ALL = 3;
/**
* Indicates that the background image is tiled to fill the entire
* window. The image is not scaled.
* The upper left corner of the image is anchored at the
* upper-left corner of the window.
*
* @see #setImageScaleMode
*
* @since Java 3D 1.3
*/
public static final int SCALE_REPEAT = 4;
/**
* Indicates that the background image is centered in the window
* and that no scaling of the image is done. The image will be
* drawn in its actual size. If the window is smaller than the
* image, the image will be clipped. If the window is larger than
* the image, the portion of the window not filled by the image
* will be filled with the background color.
*
* @see #setImageScaleMode
*
* @since Java 3D 1.3
*/
public static final int SCALE_NONE_CENTER = 5;
// Array for setting default read capabilities
private static final int[] readCapabilities = {
ALLOW_APPLICATION_BOUNDS_READ,
ALLOW_COLOR_READ,
ALLOW_GEOMETRY_READ,
ALLOW_IMAGE_READ,
ALLOW_IMAGE_SCALE_MODE_READ
};
/**
* Constructs a Background node with default parameters. The default
* values are as follows:
*
imageScaleMode
* is a value other than SCALE_NONE, SCALE_FIT_MIN, SCALE_FIT_MAX,
* SCALE_FIT_ALL, SCALE_REPEAT, or SCALE_NONE_CENTER.
* @exception CapabilityNotSetException if appropriate capability is
* not set and this object is part of live or compiled scene graph
*
* @since Java 3D 1.3
*/
public void setImageScaleMode(int imageScaleMode) {
if (isLiveOrCompiled())
if(!this.getCapability(ALLOW_IMAGE_SCALE_MODE_WRITE))
throw new CapabilityNotSetException(J3dI18N.getString("Background9"));
switch (imageScaleMode) {
case SCALE_NONE:
case SCALE_FIT_MIN:
case SCALE_FIT_MAX:
case SCALE_FIT_ALL:
case SCALE_REPEAT:
case SCALE_NONE_CENTER:
break;
default:
throw new IllegalArgumentException(J3dI18N.getString("Background11"));
}
if (isLive())
((BackgroundRetained)this.retained).setImageScaleMode(imageScaleMode);
else
((BackgroundRetained)this.retained).initImageScaleMode(imageScaleMode);
}
/**
* Retrieves the current image scale mode.
* @return the current image scale mode, one of:
* SCALE_NONE, SCALE_FIT_MIN, SCALE_FIT_MAX, SCALE_FIT_ALL,
* SCALE_REPEAT, or SCALE_NONE_CENTER.
*
* @exception CapabilityNotSetException if appropriate capability is
* not set and this object is part of live or compiled scene graph
*
* @since Java 3D 1.3
*/
public int getImageScaleMode() {
if (isLiveOrCompiled())
if(!this.getCapability(ALLOW_IMAGE_SCALE_MODE_READ))
throw new CapabilityNotSetException(J3dI18N.getString("Background10"));
return ((BackgroundRetained)this.retained).getImageScaleMode();
}
/**
* Sets the background geometry to the specified BranchGroup node.
* If non-null, this background geometry is drawn on top of
* the background color and image using a projection
* matrix that essentially puts the geometry at infinity. The geometry
* should be pre-tessellated onto a unit sphere.
* @param branch the root of the background geometry
* @exception CapabilityNotSetException if appropriate capability is
* not set and this object is part of live or compiled scene graph
* @exception IllegalSharingException if the BranchGroup node
* is a child of any Group node, or is already attached to a Locale,
* or is already referenced by another Background node.
* @exception IllegalSceneGraphException if specified branch graph
* contains an illegal node.
*/
public void setGeometry(BranchGroup branch) {
if (isLiveOrCompiled())
if(!this.getCapability(ALLOW_GEOMETRY_WRITE))
throw new CapabilityNotSetException(J3dI18N.getString("Background5"));
if (isLive())
((BackgroundRetained)this.retained).setGeometry(branch);
else
((BackgroundRetained)this.retained).initGeometry(branch);
}
/**
* Retrieves the background geometry.
* @return the BranchGroup node that is the root of the background
* geometry
* @exception CapabilityNotSetException if appropriate capability is
* not set and this object is part of live or compiled scene graph
*/
public BranchGroup getGeometry() {
if (isLiveOrCompiled())
if(!this.getCapability(ALLOW_GEOMETRY_READ))
throw new CapabilityNotSetException(J3dI18N.getString("Background6"));
return ((BackgroundRetained)this.retained).getGeometry();
}
/**
* Set the Background's application region to the specified bounds.
* This is used when the application bounding leaf is set to null.
* @param region the bounds that contains the Background's new application
* region.
* @exception CapabilityNotSetException if appropriate capability is
* not set and this object is part of live or compiled scene graph
*/
public void setApplicationBounds(Bounds region) {
if (isLiveOrCompiled())
if(!this.getCapability(ALLOW_APPLICATION_BOUNDS_WRITE))
throw new CapabilityNotSetException(J3dI18N.getString("Background7"));
if (isLive())
((BackgroundRetained)this.retained).setApplicationBounds(region);
else
((BackgroundRetained)this.retained).initApplicationBounds(region);
}
/**
* Retrieves the Background node's application bounds.
* @return this Background's application bounds information
* @exception CapabilityNotSetException if appropriate capability is
* not set and this object is part of live or compiled scene graph
*/
public Bounds getApplicationBounds() {
if (isLiveOrCompiled())
if(!this.getCapability(ALLOW_APPLICATION_BOUNDS_READ))
throw new CapabilityNotSetException(J3dI18N.getString("Background8"));
return ((BackgroundRetained)this.retained).getApplicationBounds();
}
/**
* Set the Background's application region to the specified bounding leaf.
* When set to a value other than null, this overrides the application
* bounds object.
* @param region the bounding leaf node used to specify the Background
* node's new application region.
* @exception CapabilityNotSetException if appropriate capability is
* not set and this object is part of live or compiled scene graph
*/
public void setApplicationBoundingLeaf(BoundingLeaf region) {
if (isLiveOrCompiled())
if(!this.getCapability(ALLOW_APPLICATION_BOUNDS_WRITE))
throw new CapabilityNotSetException(J3dI18N.getString("Background7"));
if (isLive())
((BackgroundRetained)this.retained).setApplicationBoundingLeaf(region);
else
((BackgroundRetained)this.retained).initApplicationBoundingLeaf(region);
}
/**
* Retrieves the Background node's application bounding leaf.
* @return this Background's application bounding leaf information
* @exception CapabilityNotSetException if appropriate capability is
* not set and this object is part of live or compiled scene graph
*/
public BoundingLeaf getApplicationBoundingLeaf() {
if (isLiveOrCompiled())
if(!this.getCapability(ALLOW_APPLICATION_BOUNDS_READ))
throw new CapabilityNotSetException(J3dI18N.getString("Background8"));
return ((BackgroundRetained)this.retained).getApplicationBoundingLeaf();
}
/**
* Creates the retained mode BackgroundRetained object that this
* Background component object will point to.
*/
@Override
void createRetained() {
this.retained = new BackgroundRetained();
this.retained.setSource(this);
}
/**
* Creates a new instance of the node. This routine is called
* by cloneTree
to duplicate the current node.
* @param forceDuplicate when set to true
, causes the
* duplicateOnCloneTree
flag to be ignored. When
* false
, the value of each node's
* duplicateOnCloneTree
variable determines whether
* NodeComponent data is duplicated or copied.cloneTree
on that branchGroup.
*
* @see Node#cloneTree
* @see Node#cloneNode
* @see Node#duplicateNode
* @see NodeComponent#setDuplicateOnCloneTree
*/
@Override
public Node cloneNode(boolean forceDuplicate) {
Background b = new Background();
b.duplicateNode(this, forceDuplicate);
return b;
}
/**
* Copies all node information from originalNode
into
* the current node. This method is called from the
* cloneNode
method which is, in turn, called by the
* cloneTree
method.
*
* For any NodeComponent
objects
* contained by the object being duplicated, each NodeComponent
* object's duplicateOnCloneTree
value is used to determine
* whether the NodeComponent
should be duplicated in the new node
* or if just a reference to the current node should be placed in the
* new node. This flag can be overridden by setting the
* forceDuplicate
parameter in the cloneTree
* method to true
.
*
*
* NOTE: Applications should not call this method directly.
* It should only be called by the cloneNode method.
*
* @param originalNode the original node to duplicate.
* @param forceDuplicate when set to true
, causes the
* duplicateOnCloneTree
flag to be ignored. When
* false
, the value of each node's
* duplicateOnCloneTree
variable determines whether
* NodeComponent data is duplicated or copied.
* @exception ClassCastException if originalNode is not an instance of
* Background
*
* @see Node#cloneTree
* @see Node#cloneNode
* @see NodeComponent#setDuplicateOnCloneTree
*/
@Override
public void duplicateNode(Node originalNode, boolean
forceDuplicate) {
checkDuplicateNode(originalNode, forceDuplicate);
}
/**
* Copies all Background information from
* originalNode
into
* the current node. This method is called from the
* cloneNode
method which is, in turn, called by the
* cloneTree
method.
*
* @param originalNode the original node to duplicate
* @param forceDuplicate when set to true
, causes the
* duplicateOnCloneTree
flag to be ignored. When
* false
, the value of each node's
* duplicateOnCloneTree
variable determines whether
* NodeComponent data is duplicated or copied.
*
* @exception RestrictedAccessException if this object is part of a live
* or compiled scenegraph.
*
* @see Node#duplicateNode
* @see Node#cloneTree
* @see NodeComponent#setDuplicateOnCloneTree
*/
@Override
void duplicateAttributes(Node originalNode, boolean forceDuplicate) {
super.duplicateAttributes(originalNode, forceDuplicate);
BackgroundRetained attr = (BackgroundRetained) originalNode.retained;
BackgroundRetained rt = (BackgroundRetained) retained;
Color3f c = new Color3f();
attr.getColor(c);
rt.initColor(c);
rt.initApplicationBounds(attr.getApplicationBounds());
rt.initGeometry(attr.getGeometry());
// issue # 563: add call to cloneTree()
rt.initGeometry((BranchGroup) (attr.getGeometry() == null ? null : attr.getGeometry().cloneTree(true)));
rt.initImage((ImageComponent2D) getNodeComponent(
attr.getImage(),
forceDuplicate,
originalNode.nodeHashtable));
// this will be updated in updateNodeReferences
rt.initApplicationBoundingLeaf(attr.getApplicationBoundingLeaf());
}
/**
* Callback used to allow a node to check if any scene graph objects
* referenced
* by that node have been duplicated via a call to cloneTree
.
* This method is called by cloneTree
after all nodes in
* the sub-graph have been duplicated. The cloned Leaf node's method
* will be called and the Leaf node can then look up any object references
* by using the getNewObjectReference
method found in the
* NodeReferenceTable
object. If a match is found, a
* reference to the corresponding object in the newly cloned sub-graph
* is returned. If no corresponding reference is found, either a
* DanglingReferenceException is thrown or a reference to the original
* object is returned depending on the value of the
* allowDanglingReferences
parameter passed in the
* cloneTree
call.
*
* NOTE: Applications should not call this method directly.
* It should only be called by the cloneTree method.
*
* @param referenceTable a NodeReferenceTableObject that contains the
* getNewObjectReference
method needed to search for
* new object instances
*
* @see NodeReferenceTable
* @see Node#cloneTree
* @see DanglingReferenceException
*/
@Override
public void updateNodeReferences(NodeReferenceTable referenceTable) {
super.updateNodeReferences(referenceTable);
BackgroundRetained rt = (BackgroundRetained) retained;
BoundingLeaf bl= rt.getApplicationBoundingLeaf();
if (bl != null) {
Object o = referenceTable.getNewObjectReference(bl);
rt.initApplicationBoundingLeaf((BoundingLeaf) o);
}
}
}