001: /*
002: * $RCSfile: SoundscapeRetained.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: import java.util.ArrayList;
035:
036: /**
037: * The SoundscapeRetained object defines all soundscape rendering state
038: * as a subclass of a Leaf node.
039: */
040: class SoundscapeRetained extends LeafRetained {
041: static final int ATTRIBUTES_CHANGED = 0x00001;
042: static final int BOUNDING_LEAF_CHANGED = 0x00002;
043: static final int APPLICATION_BOUNDS_CHANGED = 0x00004;
044:
045: /**
046: * Soundscape nodes application region
047: */
048: Bounds applicationRegion = null;
049:
050: /**
051: * The bounding leaf reference
052: */
053: BoundingLeafRetained boundingLeaf = null;
054:
055: /**
056: * The transformed Application Region
057: */
058: Bounds transformedRegion = null;
059:
060: /**
061: * Aural attributes associated with this Soundscape
062: */
063: AuralAttributesRetained attributes = null;
064:
065: // A bitmask that indicates that the something has changed.
066: int isDirty = 0xffff;
067:
068: // Target threads to be notified when sound changes
069: int targetThreads = J3dThread.UPDATE_SOUND
070: | J3dThread.SOUND_SCHEDULER;
071:
072: // Is true, if the mirror light is viewScoped
073: boolean isViewScoped = false;
074:
075: void dispatchMessage(int dirtyBit, Object argument) {
076: // Send message including a integer argument
077: J3dMessage createMessage = new J3dMessage();
078: createMessage.threads = targetThreads;
079: createMessage.type = J3dMessage.SOUNDSCAPE_CHANGED;
080: createMessage.universe = universe;
081: createMessage.args[0] = this ;
082: createMessage.args[1] = new Integer(dirtyBit);
083: createMessage.args[2] = new Integer(0);
084: createMessage.args[3] = null;
085: createMessage.args[4] = argument;
086: VirtualUniverse.mc.processMessage(createMessage);
087: }
088:
089: SoundscapeRetained() {
090: super ();
091: this .nodeType = NodeRetained.SOUNDSCAPE;
092: localBounds = new BoundingBox();
093: ((BoundingBox) localBounds).setLower(1.0, 1.0, 1.0);
094: ((BoundingBox) localBounds).setUpper(-1.0, -1.0, -1.0);
095: }
096:
097: /**
098: * Set the Soundscape's application region.
099: * @param region a region that contains the Soundscape's new application region
100: */
101: void setApplicationBounds(Bounds region) {
102: if (region != null) {
103: applicationRegion = (Bounds) region.clone();
104: if (staticTransform != null) {
105: applicationRegion.transform(staticTransform.transform);
106: }
107: } else {
108: applicationRegion = null;
109: }
110: updateTransformChange();
111: this .isDirty |= APPLICATION_BOUNDS_CHANGED;
112: dispatchMessage(APPLICATION_BOUNDS_CHANGED, region);
113:
114: if (source != null && source.isLive()) {
115: notifySceneGraphChanged(false);
116: }
117: }
118:
119: /**
120: * Get the Soundscape's application region.
121: * @return this Soundscape's application region information
122: */
123: Bounds getApplicationBounds() {
124: Bounds b = null;
125:
126: if (this .applicationRegion == null)
127: return (Bounds) null;
128: else {
129: b = (Bounds) applicationRegion.clone();
130: if (staticTransform != null) {
131: Transform3D invTransform = staticTransform
132: .getInvTransform();
133: b.transform(invTransform);
134: }
135: return b;
136: }
137: }
138:
139: /**
140: * Set the Soundscape's application region to the specified Leaf node.
141: */
142: void setApplicationBoundingLeaf(BoundingLeaf region) {
143: if (boundingLeaf != null) {
144: // Remove the soundscape as users of the original bounding leaf
145: boundingLeaf.mirrorBoundingLeaf.removeUser(this );
146: }
147: if (region != null) {
148: boundingLeaf = (BoundingLeafRetained) region.retained;
149: boundingLeaf.mirrorBoundingLeaf.addUser(this );
150: } else {
151: boundingLeaf = null;
152: }
153: updateTransformChange();
154: this .isDirty |= BOUNDING_LEAF_CHANGED;
155: dispatchMessage(BOUNDING_LEAF_CHANGED, region);
156: // QUESTION needed??
157: if (source != null && source.isLive()) {
158: notifySceneGraphChanged(false);
159: }
160: }
161:
162: /**
163: * Get the Soundscape's application region
164: */
165: BoundingLeaf getApplicationBoundingLeaf() {
166: if (boundingLeaf != null) {
167: return (BoundingLeaf) boundingLeaf.source;
168: } else {
169: return (BoundingLeaf) null;
170: }
171: }
172:
173: /**
174: * Set a set of aural attributes for this Soundscape
175: * @param attributes aural attributes to be set
176: */
177: void setAuralAttributes(AuralAttributes attributes) {
178: if (this .source.isLive()) {
179: if (this .attributes != null) {
180: this .attributes.clearLive(refCount);
181: }
182:
183: if (attributes != null) {
184: ((AuralAttributesRetained) attributes.retained)
185: .setLive(inBackgroundGroup, refCount);
186: }
187: }
188:
189: if (this .attributes != null) {
190: this .attributes.removeUser(this );
191: }
192:
193: if (attributes != null) {
194: this .attributes = (AuralAttributesRetained) attributes.retained;
195: this .attributes.addUser(this );
196: } else {
197: this .attributes = null;
198: }
199:
200: // copy all fields out of attributes and put into our copy of attributes
201: this .isDirty |= ATTRIBUTES_CHANGED;
202: dispatchMessage(ATTRIBUTES_CHANGED, attributes);
203: if (source != null && source.isLive()) {
204: notifySceneGraphChanged(false);
205: }
206: }
207:
208: /**
209: * Retrieve a reference to Aural Attributes
210: * @return attributes aural attributes to be returned
211: */
212: AuralAttributes getAuralAttributes() {
213: if (attributes != null) {
214: return ((AuralAttributes) attributes.source);
215: } else
216: return ((AuralAttributes) null);
217: }
218:
219: /*
220: // NOTE: OLD CODE
221: // The update Object function.
222: public synchronized void updateObject() {
223: if ((attributes != null) && (attributes.aaDirty)) {
224: if (attributes.mirrorAa == null) {
225: attributes.mirrorAa = new AuralAttributesRetained();
226: }
227: attributes.mirrorAa.update(attributes);
228: }
229: }
230: */
231:
232: // The update Object function.
233: synchronized void updateMirrorObject(Object[] objs) {
234: // NOTE: There doesn't seem to be a use for mirror objects since
235: // Soundscapes can't be shared.
236: // This method updates the transformed region from either bounding
237: // leaf or application bounds. Bounding leaf takes precidence.
238: Transform3D trans = null;
239: int component = ((Integer) objs[1]).intValue();
240: if ((component & BOUNDING_LEAF_CHANGED) != 0) {
241: if (this .boundingLeaf != null) {
242: transformedRegion = boundingLeaf.transformedRegion;
243: } else { // evaluate Application Region if not null
244: if (applicationRegion != null) {
245: transformedRegion = (Bounds) applicationRegion
246: .clone();
247: transformedRegion.transform(applicationRegion,
248: getLastLocalToVworld());
249: } else {
250: transformedRegion = null;
251: }
252: }
253: } else if ((component & APPLICATION_BOUNDS_CHANGED) != 0) {
254: // application bounds only used when bounding leaf null
255: if (boundingLeaf == null) {
256: transformedRegion = (Bounds) applicationRegion.clone();
257: transformedRegion.transform(applicationRegion,
258: getLastLocalToVworld());
259: } else {
260: transformedRegion = null;
261: }
262: }
263: }
264:
265: // The update tranform fields
266: synchronized void updateTransformChange() {
267: if (boundingLeaf != null) {
268: transformedRegion = boundingLeaf.transformedRegion;
269: } else { // evaluate Application Region if not null
270: if (applicationRegion != null) {
271: transformedRegion = applicationRegion
272: .copy(transformedRegion);
273: transformedRegion.transform(applicationRegion,
274: getLastLocalToVworld());
275: } else {
276: transformedRegion = null;
277: }
278: }
279: }
280:
281: void updateBoundingLeaf(long refTime) {
282: // This is necessary, if for example, the region
283: // changes from sphere to box.
284: if (boundingLeaf != null
285: && boundingLeaf.switchState.currentSwitchOn) {
286: transformedRegion = boundingLeaf.transformedRegion;
287: } else { // evaluate Application Region if not null
288: if (applicationRegion != null) {
289: transformedRegion = applicationRegion
290: .copy(transformedRegion);
291: transformedRegion.transform(applicationRegion,
292: getLastLocalToVworld());
293: } else {
294: transformedRegion = null;
295: }
296: }
297: }
298:
299: // QUESTION: not needed?
300: /*
301: synchronized void initMirrorObject(SoundscapeRetained ms) {
302: GroupRetained group;
303: Transform3D trans;
304: Bounds region = null;
305:
306: if (ms == null)
307: return;
308: }
309: ms.isDirty = isDirty;
310: ms.setApplicationBounds(getApplicationBounds());
311: ms.setApplicationBoundingLeaf(getApplicationBoundingLeaf());
312: ms.setAuralAttributes(getAuralAttributes());
313:
314: // QUESTION: no lineage of mirror node kept??
315: ms.sgSound = sgSound;
316: ms.key = null;
317: ms.mirrorSounds = new SoundscapeRetained[1];
318: ms.numMirrorSounds = 0;
319: ms.parent = parent;
320: ms.transformedRegion = null;
321: if (boundingLeaf != null) {
322: if (ms.boundingLeaf != null)
323: ms.boundingLeaf.removeUser(ms);
324: ms.boundingLeaf = boundingLeaf.mirrorBoundingLeaf;
325: // Add this mirror object as user
326: ms.boundingLeaf.addUser(ms);
327: ms.transformedRegion = ms.boundingLeaf.transformedRegion;
328: }
329: else {
330: ms.boundingLeaf = null;
331: }
332:
333: if (applicationRegion != null) {
334: ms.applicationRegion = (Bounds) applicationRegion.clone();
335: // Assign region only if bounding leaf is null
336: if (ms.transformedRegion == null) {
337: ms.transformedRegion = (Bounds) ms.applicationRegion.clone();
338: ms.transformedRegion.transform(ms.applicationRegion,
339: ms.getLastLocalToVworld());
340: }
341:
342: }
343: else {
344: ms.applicationRegion = null;
345: }
346: }
347: */
348:
349: /**
350: * This setLive routine first calls the superclass's method, then
351: * it adds itself to the list of soundscapes
352: */
353: void setLive(SetLiveState s) {
354: super .doSetLive(s);
355:
356: if (attributes != null) {
357: attributes.setLive(inBackgroundGroup, s.refCount);
358: }
359: if (s.transformTargets != null && s.transformTargets[0] != null) {
360: s.transformTargets[0].addNode(this , Targets.SND_TARGETS);
361: s.notifyThreads |= J3dThread.UPDATE_TRANSFORM;
362: }
363: // If its view Scoped, then add this list
364: // to be sent to Sound Structure
365: if ((s.viewScopedNodeList != null) && (s.viewLists != null)) {
366: s.viewScopedNodeList.add(this );
367: s.scopedNodesViewList.add(s.viewLists.get(0));
368: } else {
369: s.nodeList.add(this );
370: }
371:
372: if (inBackgroundGroup) {
373: throw new IllegalSceneGraphException(J3dI18N
374: .getString("SoundscapeRetained1"));
375: }
376:
377: if (inSharedGroup) {
378: throw new IllegalSharingException(J3dI18N
379: .getString("SoundscapeRetained0"));
380: }
381:
382: // process switch leaf
383: if (s.switchTargets != null && s.switchTargets[0] != null) {
384: s.switchTargets[0].addNode(this , Targets.SND_TARGETS);
385: }
386: switchState = (SwitchState) s.switchStates.get(0);
387: s.notifyThreads |= (J3dThread.UPDATE_SOUND | J3dThread.SOUND_SCHEDULER);
388:
389: super .markAsLive();
390: }
391:
392: /**
393: * This clearLive routine first calls the superclass's method, then
394: * it removes itself to the list of lights
395: */
396: void clearLive(SetLiveState s) {
397: super .clearLive(s);
398: if (s.switchTargets != null && s.switchTargets[0] != null) {
399: s.switchTargets[0].addNode(this , Targets.SND_TARGETS);
400: }
401:
402: if (attributes != null) {
403: attributes.clearLive(s.refCount);
404: }
405: if (s.transformTargets != null && s.transformTargets[0] != null) {
406: s.transformTargets[0].addNode(this , Targets.SND_TARGETS);
407: s.notifyThreads |= J3dThread.UPDATE_TRANSFORM;
408: }
409: // If its view Scoped, then add this list
410: // to be sent to Sound Structure
411: if ((s.viewScopedNodeList != null) && (s.viewLists != null)) {
412: s.viewScopedNodeList.add(this );
413: s.scopedNodesViewList.add(s.viewLists.get(0));
414: } else {
415: s.nodeList.add(this );
416: }
417: s.notifyThreads |= (J3dThread.UPDATE_SOUND | J3dThread.SOUND_SCHEDULER);
418: }
419:
420: // Simply pass along to the NodeComponents
421: /*
422: void compile(CompileState compState) {
423: setCompiled();
424:
425: if (attributes != null)
426: attributes.compile(compState);
427: }
428: */
429:
430: // This makes this sound look just like the one passed in
431: void update(SoundscapeRetained ss) {
432: applicationRegion = (Bounds) ss.applicationRegion.clone();
433: attributes = ss.attributes;
434: }
435:
436: void mergeTransform(TransformGroupRetained xform) {
437: super .mergeTransform(xform);
438: if (applicationRegion != null) {
439: applicationRegion.transform(xform.transform);
440: }
441: }
442:
443: void getMirrorObjects(ArrayList leafList, HashKey key) {
444: leafList.add(this);
445: }
446: }
|