001: /*
002: * $RCSfile: PointSoundRetained.java,v $
003: *
004: * Copyright 1996-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:28 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import java.lang.Math;
035: import java.net.URL;
036: import javax.vecmath.Point3f;
037: import javax.vecmath.Point3d;
038: import javax.vecmath.Point2f;
039:
040: /**
041: * The PointSoundRetained node (a sub-class of the SoundRetained node) defines
042: * a spatially-located sound source whose waves radiate uniformly in all
043: * directions from a given location in space.
044: */
045:
046: class PointSoundRetained extends SoundRetained {
047: /**
048: * Origin of Sound source in Listener's space.
049: */
050: Point3f position = new Point3f(0.0f, 0.0f, 0.0f);
051:
052: /**
053: * The transformed position of this sound
054: */
055: Point3f xformPosition = new Point3f();
056: Transform3D trans = new Transform3D();
057:
058: // Pairs of distances and gain scale factors that define piecewise linear
059: // gain attenuation between each pair.
060: float[] attenuationDistance;
061: float[] attenuationGain;
062:
063: PointSoundRetained() {
064: this .nodeType = NodeRetained.POINTSOUND;
065: }
066:
067: /**
068: * Sets this sound's location from the vector provided.
069: * @param position the new location
070: */
071: void setPosition(Point3f position) {
072: if (staticTransform != null) {
073: staticTransform.transform
074: .transform(position, this .position);
075: } else {
076: this .position.set(position);
077: }
078:
079: getLastLocalToVworld().transform(position, xformPosition);
080:
081: dispatchAttribChange(POSITION_DIRTY_BIT, (new Point3f(
082: this .position)));
083: if (source != null && source.isLive()) {
084: notifySceneGraphChanged(false);
085: }
086: }
087:
088: /**
089: * Sets this sound's position from the three values provided.
090: * @param x the new x position
091: * @param y the new y position
092: * @param z the new z position
093: */
094: void setPosition(float x, float y, float z) {
095: position.x = x;
096: position.y = y;
097: position.z = z;
098: if (staticTransform != null) {
099: staticTransform.transform.transform(this .position);
100: }
101:
102: getLastLocalToVworld().transform(position, xformPosition);
103:
104: dispatchAttribChange(POSITION_DIRTY_BIT, (new Point3f(
105: this .position)));
106: if (source != null && source.isLive()) {
107: notifySceneGraphChanged(false);
108: }
109: }
110:
111: /**
112: * Retrieves this sound's location and places it in the vector provided.
113: * @param position the variable to receive the location vector
114: */
115: void getPosition(Point3f position) {
116: if (staticTransform != null) {
117: Transform3D invTransform = staticTransform
118: .getInvTransform();
119: invTransform.transform(this .position, position);
120: } else {
121: position.set(this .position);
122: }
123: }
124:
125: void getXformPosition(Point3f position) {
126: position.set(this .xformPosition);
127: }
128:
129: /**
130: * Sets this sound's distance gain attenuation - where gain scale factor
131: * is applied to sound based on distance listener is from sound source.
132: * @param distance attenuation pairs of (distance,gain-scale-factor)
133: */
134: void setDistanceGain(Point2f[] attenuation) {
135: // if attenuation array null set both attenuation components to null
136: if (attenuation == null) {
137: this .attenuationDistance = null;
138: this .attenuationGain = null;
139: // QUESTION: is this needed so that dispatch***() doesn't
140: // fail with null?
141: return;
142: }
143:
144: int attenuationLength = attenuation.length;
145: this .attenuationDistance = new float[attenuationLength];
146: this .attenuationGain = new float[attenuationLength];
147: for (int i = 0; i < attenuationLength; i++) {
148: this .attenuationDistance[i] = attenuation[i].x;
149: this .attenuationGain[i] = attenuation[i].y;
150: }
151: dispatchAttribChange(DISTANCE_GAIN_DIRTY_BIT, attenuation);
152: if (source != null && source.isLive()) {
153: notifySceneGraphChanged(false);
154: }
155: }
156:
157: /**
158: * Sets this sound's distance gain given separate arrays.
159: * applied to sound based on distance listener is from sound source.
160: * @param distance array of monotonically-increasing floats.
161: * @param gain array of amplitude scale factors associated with distances.
162: */
163: void setDistanceGain(float[] distance, float[] gain) {
164: // if distance or gain arrays are null then treat both as null
165: if (distance == null) {
166: this .attenuationDistance = null;
167: this .attenuationGain = null;
168: // QUESTION: is this needed so that dispatch***() doesn't
169: // fail with null?
170: return;
171: }
172:
173: int gainLength = gain.length;
174: int distanceLength = distance.length;
175: this .attenuationDistance = new float[distanceLength];
176: this .attenuationGain = new float[distanceLength];
177: // Copy the distance array into nodes field
178: System.arraycopy(distance, 0, this .attenuationDistance, 0,
179: distanceLength);
180: // Copy the gain array an array of same length as the distance array
181: if (distanceLength <= gainLength) {
182: System.arraycopy(gain, 0, this .attenuationGain, 0,
183: distanceLength);
184: } else {
185: System.arraycopy(gain, 0, this .attenuationGain, 0,
186: gainLength);
187: // Extend gain array to length of distance array
188: // replicate last gain values.
189: for (int i = gainLength; i < distanceLength; i++) {
190: this .attenuationGain[i] = gain[gainLength - 1];
191: }
192: }
193: Point2f[] attenuation = new Point2f[distanceLength];
194: for (int i = 0; i < distanceLength; i++) {
195: attenuation[i] = new Point2f(this .attenuationDistance[i],
196: this .attenuationGain[i]);
197: }
198: dispatchAttribChange(DISTANCE_GAIN_DIRTY_BIT, attenuation);
199: if (source != null && source.isLive()) {
200: notifySceneGraphChanged(false);
201: }
202: }
203:
204: /**
205: * Gets this sound's distance attenuation array length
206: * @return distance gain attenuation array length
207: */
208: int getDistanceGainLength() {
209: if (attenuationDistance == null)
210: return 0;
211: else
212: return this .attenuationDistance.length;
213: }
214:
215: /**
216: * Retieves sound's distance attenuation
217: * Put the contents of the two separate distance and gain arrays into
218: * an array of Point2f.
219: * @param attenuation containing distance attenuation pairs
220: */
221: void getDistanceGain(Point2f[] attenuation) {
222: // write into arrays passed in, don't do a new
223: if (attenuation == null)
224: return;
225: if (this .attenuationDistance == null
226: || this .attenuationGain == null)
227: return;
228: int attenuationLength = attenuation.length;
229: // attenuationDistance and Gain array lengths should be the same
230: int distanceLength = this .attenuationDistance.length;
231: if (distanceLength > attenuationLength)
232: distanceLength = attenuationLength;
233: for (int i = 0; i < distanceLength; i++) {
234: attenuation[i].x = attenuationDistance[i];
235: attenuation[i].y = attenuationGain[i];
236: }
237: }
238:
239: /**
240: * Retieves this sound's attenuation distance and gain arrays, returned in
241: * separate arrays.
242: * @param distance array of monotonically-increasing floats.
243: * @param gain array of amplitude scale factors associated with distances.
244: */
245: void getDistanceGain(float[] distance, float[] gain) {
246: // write into arrays passed in, don't do a new
247: if (distance == null || gain == null)
248: return;
249: if (this .attenuationDistance == null
250: || this .attenuationGain == null)
251: return;
252: // These two array length should be the same
253: int attenuationLength = this .attenuationDistance.length;
254: int distanceLength = distance.length;
255: if (distanceLength > attenuationLength)
256: distanceLength = attenuationLength;
257: System.arraycopy(this .attenuationDistance, 0, distance, 0,
258: distanceLength);
259: attenuationLength = this .attenuationDistance.length;
260: int gainLength = gain.length;
261: if (gainLength > attenuationLength)
262: gainLength = attenuationLength;
263: System.arraycopy(this .attenuationGain, 0, gain, 0, gainLength);
264: }
265:
266: /**
267: * This updates the positional fields of point sound.
268: *
269: * Distance gain attenuation field not maintained in mirror object.
270: */
271: void updateMirrorObject(Object[] objs) {
272: if (debugFlag)
273: debugPrint("PointSoundRetained:updateMirrorObj()");
274: int component = ((Integer) objs[1]).intValue();
275: int numSnds = ((Integer) objs[2]).intValue();
276: SoundRetained[] mSnds = (SoundRetained[]) objs[3];
277: if (component == -1) {
278: // update every field
279: initMirrorObject(((PointSoundRetained) objs[2]));
280: return;
281: }
282: if ((component & POSITION_DIRTY_BIT) != 0) {
283: for (int i = 0; i < numSnds; i++) {
284: PointSoundRetained point = (PointSoundRetained) mSnds[i];
285: Object o = objs[4];
286: if (o instanceof Point3f) {
287: point.position = (Point3f) objs[4];
288: point.getLastLocalToVworld().transform(
289: point.position, point.xformPosition);
290: }
291: }
292: }
293:
294: // call the parent's mirror object update routine
295: super .updateMirrorObject(objs);
296: }
297:
298: synchronized void initMirrorObject(PointSoundRetained ms) {
299: super .initMirrorObject(ms);
300: ms.position.set(this .position);
301: ms.xformPosition.set(this .xformPosition);
302: }
303:
304: // Called on the mirror object
305: void updateTransformChange() {
306: super .updateTransformChange();
307: getLastLocalToVworld().transform(position, xformPosition);
308: // set flag looked at by Scheduler to denote Transform change
309: // this flag will force resneding transformed position to AudioDevice
310: if (debugFlag)
311: debugPrint("PointSoundRetained xformPosition is ("
312: + xformPosition.x + ", " + xformPosition.y + ", "
313: + xformPosition.z + ")");
314: }
315:
316: void mergeTransform(TransformGroupRetained xform) {
317: super.mergeTransform(xform);
318: xform.transform.transform(position, position);
319: }
320: }
|