001: /*
002: * $RCSfile: Soundscape.java,v $
003: *
004: * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
006: *
007: * This code is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License version 2 only, as
009: * published by the Free Software Foundation. Sun designates this
010: * particular file as subject to the "Classpath" exception as provided
011: * by Sun in the LICENSE file that accompanied this code.
012: *
013: * This code is distributed in the hope that it will be useful, but WITHOUT
014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: * version 2 for more details (a copy is included in the LICENSE file that
017: * accompanied this code).
018: *
019: * You should have received a copy of the GNU General Public License version
020: * 2 along with this work; if not, write to the Free Software Foundation,
021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
022: *
023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
024: * CA 95054 USA or visit www.sun.com if you need additional information or
025: * have any questions.
026: *
027: * $Revision: 1.6 $
028: * $Date: 2008/02/28 20:17:30 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: /**
035: * The Soundscape Leaf Node defines the attributes that characterize the
036: * listener's environment as it pertains to sound. This node defines an
037: * application region and an associated aural attribute component object
038: * that controls reverberation and atmospheric properties that affect sound
039: * source rendering. Multiple Soundscape nodes can be included in a single
040: * scene graph.
041: * <P>
042: * The Soundscape application region, different from a Sound node's scheduling
043: * region, is used to select which Soundscape (and thus which aural attribute
044: * object) is to be applied to the sounds being rendered. This selection is
045: * based on the position of the ViewPlatform (i.e., the listener), not the
046: * position of the sound.
047: * <P>
048: * It will be common that multiple Soundscape regions are contained within a
049: * scene graph. For example, two Soundscape regions within a single space the
050: * listener can move about: a region with a large open area on the right, and
051: * a smaller more constricted, less reverberant area on the left. The rever-
052: * beration attributes for these two regions could be set to approximate their
053: * physical differences so that active sounds are rendered differently depending
054: * on which region the listener is in.
055: */
056: public class Soundscape extends Leaf {
057:
058: // Constants
059: //
060: // These flags, when enabled using the setCapability method, allow an
061: // application to invoke methods that respectively read and write the
062: // application region and the aural attributes. These capability flags
063: // are enforced only when the node is part of a live or compiled scene
064: // graph.
065:
066: /**
067: * For Soundscape component objects, specifies that this object
068: * allows read access to its application bounds
069: */
070: public static final int ALLOW_APPLICATION_BOUNDS_READ = CapabilityBits.SOUNDSCAPE_ALLOW_APPLICATION_BOUNDS_READ;
071:
072: /**
073: * For Soundscape component objects, specifies that this object
074: * allows write access to its application bounds
075: */
076: public static final int ALLOW_APPLICATION_BOUNDS_WRITE = CapabilityBits.SOUNDSCAPE_ALLOW_APPLICATION_BOUNDS_WRITE;
077:
078: /**
079: * For Soundscape component objects, specifies that this object
080: * allows the reading of it's aural attributes information
081: */
082: public static final int ALLOW_ATTRIBUTES_READ = CapabilityBits.SOUNDSCAPE_ALLOW_ATTRIBUTES_READ;
083:
084: /**
085: * For Soundscape component objects, specifies that this object
086: * allows the writing of it's aural attribute information
087: */
088: public static final int ALLOW_ATTRIBUTES_WRITE = CapabilityBits.SOUNDSCAPE_ALLOW_ATTRIBUTES_WRITE;
089:
090: // Array for setting default read capabilities
091: private static final int[] readCapabilities = {
092: ALLOW_APPLICATION_BOUNDS_READ, ALLOW_ATTRIBUTES_READ };
093:
094: /**
095: * Constructs and initializes a new Sound node using following
096: * defaults:
097: *<UL> application region: null (no active region)</UL>
098: *<UL> aural attributes: null (uses default aural attributes)</UL>
099: */
100: public Soundscape() {
101: // Just use default values
102: // set default read capabilities
103: setDefaultReadCapabilities(readCapabilities);
104: }
105:
106: /**
107: * Constructs and initializes a new Sound node using specified
108: * parameters
109: * @param region application region
110: * @param attributes array of aural attribute component objects
111: */
112: public Soundscape(Bounds region, AuralAttributes attributes) {
113: // set default read capabilities
114: setDefaultReadCapabilities(readCapabilities);
115:
116: ((SoundscapeRetained) this .retained)
117: .setApplicationBounds(region);
118: ((SoundscapeRetained) this .retained)
119: .setAuralAttributes(attributes);
120: }
121:
122: /**
123: * Creates the retained mode SoundscapeRetained object that this
124: * component object will point to.
125: */
126: void createRetained() {
127: this .retained = new SoundscapeRetained();
128: this .retained.setSource(this );
129: }
130:
131: /**
132: * Set the Soundscape's application region to the specified bounds
133: * specified in local coordinates of this leaf node. The aural
134: * attributes associated with this Soundscape are used to render
135: * the active sounds when this application region intersects the
136: * ViewPlatform's activation volume. The getApplicationBounds method
137: * returns a new Bounds object.
138: * This region is used when the application bounding leaf is null.
139: * @param region the bounds that contains the Soundscape's new application
140: * region.
141: * @exception CapabilityNotSetException if appropriate capability is
142: * not set and this object is part of live or compiled scene graph
143: */
144: public void setApplicationBounds(Bounds region) {
145: if (isLiveOrCompiled())
146: if (!this .getCapability(ALLOW_APPLICATION_BOUNDS_WRITE))
147: throw new CapabilityNotSetException(J3dI18N
148: .getString("Soundscape0"));
149:
150: ((SoundscapeRetained) this .retained)
151: .setApplicationBounds(region);
152: }
153:
154: /**
155: * Retrieves the Soundscape node's application bounds.
156: * @return this Soundscape's application bounds information
157: * @exception CapabilityNotSetException if appropriate capability is
158: * not set and this object is part of live or compiled scene graph
159: */
160: public Bounds getApplicationBounds() {
161: if (isLiveOrCompiled())
162: if (!this .getCapability(ALLOW_APPLICATION_BOUNDS_READ))
163: throw new CapabilityNotSetException(J3dI18N
164: .getString("Soundscape1"));
165:
166: return ((SoundscapeRetained) this .retained)
167: .getApplicationBounds();
168: }
169:
170: /**
171: * Set the Soundscape's application region to the specified bounding leaf.
172: * When set to a value other than null, this overrides the application
173: * bounds object.
174: * @param region the bounding leaf node used to specify the Soundscape
175: * node's new application region.
176: * @exception CapabilityNotSetException if appropriate capability is
177: * not set and this object is part of live or compiled scene graph
178: */
179: public void setApplicationBoundingLeaf(BoundingLeaf region) {
180: if (isLiveOrCompiled())
181: if (!this .getCapability(ALLOW_APPLICATION_BOUNDS_WRITE))
182: throw new CapabilityNotSetException(J3dI18N
183: .getString("Soundscape0"));
184:
185: ((SoundscapeRetained) this .retained)
186: .setApplicationBoundingLeaf(region);
187: }
188:
189: /**
190: * Retrieves the Soundscape node's application bounding leaf.
191: * @return this Soundscape's application bounding leaf information
192: * @exception CapabilityNotSetException if appropriate capability is
193: * not set and this object is part of live or compiled scene graph
194: */
195: public BoundingLeaf getApplicationBoundingLeaf() {
196: if (isLiveOrCompiled())
197: if (!this .getCapability(ALLOW_APPLICATION_BOUNDS_READ))
198: throw new CapabilityNotSetException(J3dI18N
199: .getString("Soundscape1"));
200:
201: return ((SoundscapeRetained) this .retained)
202: .getApplicationBoundingLeaf();
203: }
204:
205: /**
206: * Set a set of aural attributes for this Soundscape
207: * @param attributes aural attributes
208: * @exception CapabilityNotSetException if appropriate capability is
209: * not set and this object is part of live or compiled scene graph
210: */
211: public void setAuralAttributes(AuralAttributes attributes) {
212: if (isLiveOrCompiled())
213: if (!this .getCapability(ALLOW_ATTRIBUTES_WRITE))
214: throw new CapabilityNotSetException(J3dI18N
215: .getString("Soundscape4"));
216:
217: ((SoundscapeRetained) this .retained)
218: .setAuralAttributes(attributes);
219: }
220:
221: /**
222: * Retrieve reference of Aural Attributes
223: * @return reference to aural attributes
224: * @exception CapabilityNotSetException if appropriate capability is
225: * not set and this object is part of live or compiled scene graph
226: */
227: public AuralAttributes getAuralAttributes() {
228: if (isLiveOrCompiled())
229: if (!this .getCapability(ALLOW_ATTRIBUTES_READ))
230: throw new CapabilityNotSetException(J3dI18N
231: .getString("Soundscape5"));
232:
233: return ((SoundscapeRetained) this .retained)
234: .getAuralAttributes();
235: }
236:
237: /**
238: * Creates a new instance of the node. This routine is called
239: * by <code>cloneTree</code> to duplicate the current node.
240: * @param forceDuplicate when set to <code>true</code>, causes the
241: * <code>duplicateOnCloneTree</code> flag to be ignored. When
242: * <code>false</code>, the value of each node's
243: * <code>duplicateOnCloneTree</code> variable determines whether
244: * NodeComponent data is duplicated or copied.
245: *
246: * @see Node#cloneTree
247: * @see Node#cloneNode
248: * @see Node#duplicateNode
249: * @see NodeComponent#setDuplicateOnCloneTree
250: */
251: public Node cloneNode(boolean forceDuplicate) {
252: Soundscape s = new Soundscape();
253: s.duplicateNode(this , forceDuplicate);
254: return s;
255: }
256:
257: /**
258: * Copies all node information from <code>originalNode</code> into
259: * the current node. This method is called from the
260: * <code>cloneNode</code> method which is, in turn, called by the
261: * <code>cloneTree</code> method.
262: * <P>
263: * For any <code>NodeComponent</code> objects
264: * contained by the object being duplicated, each <code>NodeComponent</code>
265: * object's <code>duplicateOnCloneTree</code> value is used to determine
266: * whether the <code>NodeComponent</code> should be duplicated in the new node
267: * or if just a reference to the current node should be placed in the
268: * new node. This flag can be overridden by setting the
269: * <code>forceDuplicate</code> parameter in the <code>cloneTree</code>
270: * method to <code>true</code>.
271: * <br>
272: * NOTE: Applications should <i>not</i> call this method directly.
273: * It should only be called by the cloneNode method.
274: *
275: * @param originalNode the original node to duplicate.
276: * @param forceDuplicate when set to <code>true</code>, causes the
277: * <code>duplicateOnCloneTree</code> flag to be ignored. When
278: * <code>false</code>, the value of each node's
279: * <code>duplicateOnCloneTree</code> variable determines whether
280: * NodeComponent data is duplicated or copied.
281: * @exception ClassCastException if originalNode is not an instance of
282: * <code>Soundscape</code>
283: *
284: * @see Node#cloneTree
285: * @see Node#cloneNode
286: * @see NodeComponent#setDuplicateOnCloneTree
287: */
288: public void duplicateNode(Node originalNode, boolean forceDuplicate) {
289: checkDuplicateNode(originalNode, forceDuplicate);
290: }
291:
292: /**
293: * Copies all Soundscape information from
294: * <code>originalNode</code> into
295: * the current node. This method is called from the
296: * <code>cloneNode</code> method which is, in turn, called by the
297: * <code>cloneTree</code> method.<P>
298: *
299: * @param originalNode the original node to duplicate.
300: * @param forceDuplicate when set to <code>true</code>, causes the
301: * <code>duplicateOnCloneTree</code> flag to be ignored. When
302: * <code>false</code>, the value of each node's
303: * <code>duplicateOnCloneTree</code> variable determines whether
304: * NodeComponent data is duplicated or copied.
305: *
306: * @exception RestrictedAccessException if this object is part of a live
307: * or compiled scenegraph.
308: *
309: * @see Node#duplicateNode
310: * @see Node#cloneTree
311: * @see NodeComponent#setDuplicateOnCloneTree
312: */
313: void duplicateAttributes(Node originalNode, boolean forceDuplicate) {
314: super .duplicateAttributes(originalNode, forceDuplicate);
315:
316: SoundscapeRetained attr = (SoundscapeRetained) originalNode.retained;
317: SoundscapeRetained rt = (SoundscapeRetained) retained;
318:
319: rt.setApplicationBounds(attr.getApplicationBounds());
320:
321: rt.setAuralAttributes((AuralAttributes) getNodeComponent(attr
322: .getAuralAttributes(), forceDuplicate,
323: originalNode.nodeHashtable));
324:
325: // the following reference will set correctly in updateNodeReferences
326: rt
327: .setApplicationBoundingLeaf(attr
328: .getApplicationBoundingLeaf());
329: }
330:
331: /**
332: * Callback used to allow a node to check if any scene graph objects
333: * referenced
334: * by that node have been duplicated via a call to <code>cloneTree</code>.
335: * This method is called by <code>cloneTree</code> after all nodes in
336: * the sub-graph have been duplicated. The cloned Leaf node's method
337: * will be called and the Leaf node can then look up any object references
338: * by using the <code>getNewObjectReference</code> method found in the
339: * <code>NodeReferenceTable</code> object. If a match is found, a
340: * reference to the corresponding object in the newly cloned sub-graph
341: * is returned. If no corresponding reference is found, either a
342: * DanglingReferenceException is thrown or a reference to the original
343: * object is returned depending on the value of the
344: * <code>allowDanglingReferences</code> parameter passed in the
345: * <code>cloneTree</code> call.
346: * <p>
347: * NOTE: Applications should <i>not</i> call this method directly.
348: * It should only be called by the cloneTree method.
349: *
350: * @param referenceTable a NodeReferenceTableObject that contains the
351: * <code>getNewObjectReference</code> method needed to search for
352: * new object instances.
353: * @see NodeReferenceTable
354: * @see Node#cloneTree
355: * @see DanglingReferenceException
356: */
357: public void updateNodeReferences(NodeReferenceTable referenceTable) {
358:
359: SoundscapeRetained rt = (SoundscapeRetained) retained;
360:
361: BoundingLeaf bl = rt.getApplicationBoundingLeaf();
362:
363: if (bl != null) {
364: Object o = referenceTable.getNewObjectReference(bl);
365: rt.setApplicationBoundingLeaf((BoundingLeaf) o);
366: }
367: }
368:
369: }
|