All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax.media.j3d.SoundStructure Maven / Gradle / Ivy

/*
 * Copyright 1998-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.Arrays;
import java.util.HashMap;

/**
 * A sound structure is a object that organizes Sounds and
 * soundscapes.
 * This structure parallels the RenderingEnv structure and
 * is used for sounds
 */

class SoundStructure extends J3dStructure {
    /**
     * The list of Sound nodes
     */
    UnorderList nonViewScopedSounds = new UnorderList(SoundRetained.class);
    HashMap viewScopedSounds = new HashMap();

    /**
     * The list of Soundscapes
     */
    UnorderList nonViewScopedSoundscapes = new UnorderList(SoundscapeRetained.class);
    HashMap viewScopedSoundscapes = new HashMap();

    /**
     * The list of view platforms
     */
    UnorderList viewPlatforms = new UnorderList(ViewPlatformRetained.class);

    /**
     * A bounds used for getting a view platform scheduling BoundingSphere
     */
    BoundingSphere tempSphere = new BoundingSphere();
    BoundingSphere vpsphere = new BoundingSphere();

    // ArrayList of leafRetained object whose mirrorObjects
    // should be updated
    ArrayList objList = new ArrayList();

    // ArrayList of leafRetained object whose boundingleaf xform
    // should be updated
    ArrayList xformChangeList = new ArrayList();

   // ArrayList of switches that have changed
    ArrayList switchChangeLeafNodes = new ArrayList();
    ArrayList switchChangeLeafMasks = new ArrayList();

    // variables for processing transform messages
    boolean transformMsg = false;
    UpdateTargets targets = null;

    /**
     * This constructor does nothing
     */
    SoundStructure(VirtualUniverse u) {
	super(u, J3dThread.UPDATE_SOUND);
        if (debugFlag)
            debugPrint("SoundStructure constructed");
    }

    @Override
    void processMessages(long referenceTime) {
	J3dMessage messages[] = getMessages(referenceTime);
	int nMsg = getNumMessage();
	J3dMessage m;

	if (nMsg <= 0) {
	    return;
	}


	for (int i=0; i < nMsg; i++) {
	    m = messages[i];

	    switch (m.type) {
	    case J3dMessage.INSERT_NODES :
		// Prioritize retained and non-retained sounds for this view
		insertNodes(m);
		break;
	    case J3dMessage.REMOVE_NODES:
		removeNodes(m);
		break;
	    case J3dMessage.SOUND_ATTRIB_CHANGED:
		changeNodeAttrib(m);
		break;
	    case J3dMessage.SOUND_STATE_CHANGED:
		changeNodeState(m);
		break;
	    case J3dMessage.SOUNDSCAPE_CHANGED:
	    case J3dMessage.AURALATTRIBUTES_CHANGED:
		// XXXX: this needs to be changed
		changeNodeAttrib(m);
		break;
	    case J3dMessage.TRANSFORM_CHANGED:
		transformMsg = true;
		break;
	    case J3dMessage.SWITCH_CHANGED:
                // This method isn't implemented yet.
                // processSwitchChanged(m);
		// may need to process dirty switched-on transform
		if (universe.transformStructure.getLazyUpdate()) {
		    transformMsg = true;
		}
		break;
	    case J3dMessage.VIEWSPECIFICGROUP_CHANGED:
		updateViewSpecificGroupChanged(m);
		break;
	    // XXXX: case J3dMessage.BOUNDINGLEAF_CHANGED
	    }

	    /*
	    // NOTE: this should already be handled by including/ORing
	    //       SOUND_SCHEDULER in targetThread for these message types!!
	    // Dispatch a message about a sound change
	    ViewPlatformRetained vpLists[] = (ViewPlatformRetained [])
		viewPlatforms.toArray(false);

	    // QUESTION: can I just use this message to pass to all the Sound Bins
	    for (int k=viewPlatforms.arraySize()- 1; k>=0; k--) {
		View[] views = vpLists[k].getViewList();
		for (int j=(views.length-1); j>=0; j--) {
		    View v = (View)(views[j]);
		    m.view = v;
		    VirtualUniverse.mc.processMessage(m);
		}
	    }
	    */
	    m.decRefcount();
	}
	if (transformMsg) {
	    targets = universe.transformStructure.getTargetList();
	    updateTransformChange(targets, referenceTime);
	    transformMsg = false;
	    targets = null;
	}

	Arrays.fill(messages, 0, nMsg, null);
    }

    void insertNodes(J3dMessage m) {
	Object[] nodes = (Object[])m.args[0];
	ArrayList viewScopedNodes = (ArrayList)m.args[3];
	ArrayList> scopedNodesViewList = (ArrayList>)m.args[4];

	for (int i=0; i vl = scopedNodesViewList.get(i);
		int vsize = vl.size();
		if (node instanceof SoundRetained) {
		    ((SoundRetained)node).isViewScoped = true;
		    for (int k = 0; k < vsize; k++) {
			View view = vl.get(k);
			addScopedSound((SoundRetained) node, view);
		    }
		}
		else if (node instanceof SoundscapeRetained) {
		    ((SoundscapeRetained)node).isViewScoped = true;
		    for (int k = 0; k < vsize; k++) {
			View view = vl.get(k);
			addScopedSoundscape((SoundscapeRetained) node, view);
		    }
		}
	    }
	}
	    /*
	    // XXXX:
            if (node instanceof AuralAttributesRetained) {
            }
            else if (node instanceof ViewPlatformRetained) {
                addViewPlatform((ViewPlatformRetained) node);
            }
	    */
    }


    /**
     * Add sound to sounds list.
     */
    void addScopedSound(SoundRetained mirSound, View view) {
        if (debugFlag)
            debugPrint("SoundStructure.addSound()");
	ArrayList l = (ArrayList) viewScopedSounds.get(view);
        if (l == null) {
	    l = new ArrayList();
	    viewScopedSounds.put(view, l);
        }
	l.add(mirSound);
    } // end addSound()

    void addNonScopedSound(SoundRetained mirSound) {
        if (debugFlag)
            debugPrint("SoundStructure.addSound()");
        nonViewScopedSounds.add(mirSound);
    } // end addSound()


    void addScopedSoundscape(SoundscapeRetained soundscape, View view) {
        if (debugFlag)
            debugPrint("SoundStructure.addSoundscape()");
	ArrayList l = (ArrayList) viewScopedSoundscapes.get(view);
        if (l == null) {
	    l = new ArrayList();
	    viewScopedSoundscapes.put(view, l);
        }
	l.add(soundscape);
    }

    void addNonSoundscape(SoundscapeRetained soundscape) {
        if (debugFlag)
            debugPrint("SoundStructure.addSoundscape()");
        nonViewScopedSoundscapes.add(soundscape);
    }


    @Override
    void removeNodes(J3dMessage m) {
	Object[] nodes = (Object[])m.args[0];
	ArrayList viewScopedNodes = (ArrayList)m.args[3];
	ArrayList> scopedNodesViewList = (ArrayList>)m.args[4];

	for (int i=0; i vl = scopedNodesViewList.get(i);
		// If the node object is scoped to this view, then ..
		int vsize = vl.size();

		if (node instanceof SoundRetained) {
		    ((SoundRetained)node).isViewScoped = false;
		    for (int k = 0; k < vsize; k++) {
			View view = vl.get(k);
			deleteScopedSound((SoundRetained) node, view);
		    }
		}
		else if (node instanceof SoundscapeRetained) {
		    ((SoundscapeRetained)node).isViewScoped = false;
		    for (int k = 0; k < vsize; k++) {
			View view = vl.get(k);
			deleteScopedSoundscape((SoundscapeRetained) node, view);
		    }
		}
	    }
	}
    }

    void deleteNonScopedSound(SoundRetained sound) {
        if (!nonViewScopedSounds.isEmpty()) {
            // find sound in list and remove it
            int index = nonViewScopedSounds.indexOf(sound);
            nonViewScopedSounds.remove(index);
        }
    }

    void deleteNonScopedSoundscape(SoundscapeRetained soundscape) {
        boolean error = nonViewScopedSoundscapes.remove(soundscape);
    }

    void deleteScopedSound(SoundRetained sound, View view) {
	ArrayList l = (ArrayList) viewScopedSounds.get(view);
        if (!l.isEmpty()) {
            // find sound in list and remove it
            int index = l.indexOf(sound);
            l.remove(index);
        }
	if (l.isEmpty())
	    viewScopedSounds.remove(view);
    }

    void deleteScopedSoundscape(SoundscapeRetained soundscape, View view) {
	ArrayList l = (ArrayList) viewScopedSoundscapes.get(view);
        if (!l.isEmpty()) {
            // find sound in list and remove it
            int index = l.indexOf(soundscape);
            l.remove(index);
        }
	if (l.isEmpty())
	    viewScopedSoundscapes.remove(view);

    }

    void changeNodeAttrib(J3dMessage m) {
        int attribDirty;
        Object node = m.args[0];
        Object value = m.args[1];
        if (debugFlag)
            debugPrint("SoundStructure.changeNodeAttrib:");

        if (node instanceof SoundRetained) {
            attribDirty = ((Integer)value).intValue();
            if (debugFlag)
                debugPrint("         Sound node dirty bit = " + attribDirty);
            if ((attribDirty & SoundRetained.PRIORITY_DIRTY_BIT) > 0) {
		// XXXX: shuffle in SoundScheduler
		/*
                shuffleSound((SoundRetained) node);
		*/
            }
            if ((attribDirty & SoundRetained.SOUND_DATA_DIRTY_BIT) > 0) {
                    loadSound((SoundRetained) node, true);
            }
            ((SoundRetained)node).updateMirrorObject(m.args);
        }
        if (node instanceof SoundscapeRetained) {
/*
            attribDirty = ((Integer)value).intValue();
            if (((attribDirty & SoundscapeRetained.BOUNDING_LEAF_CHANGED) != 0) ||
                ((attribDirty & SoundscapeRetained.APPLICATION_BOUNDS_CHANGED) != 0) ) {
*/
                ((SoundscapeRetained)node).updateTransformChange();
/*
            }
*/
// XXXX: have no dirty flag for soundscape, just auralAttributes...
//          what if reference to AA changes in soundscape???
        }

    }


    void changeNodeState(J3dMessage m) {
        int stateDirty;
        Object node = m.args[0];
        Object value = m.args[1];
        if (debugFlag)
            debugPrint("SoundStructure.changeNodeState:");
        if (node instanceof SoundRetained) {
            stateDirty = ((Integer)value).intValue();
            if (debugFlag)
                debugPrint("         Sound node dirty bit = " + stateDirty);
            if ((stateDirty & SoundRetained.LIVE_DIRTY_BIT) > 0) {
                    loadSound((SoundRetained) node, false);
            }
            if ((stateDirty & SoundRetained.ENABLE_DIRTY_BIT) > 0) {
                    enableSound((SoundRetained) node);
            }
            ((SoundRetained)node).updateMirrorObject(m.args);
        }
    }

    // return true if one of ViewPlatforms intersect region
    boolean intersect(Bounds region) {
        if (region == null)
            return false;

        ViewPlatformRetained vpLists[] = (ViewPlatformRetained [])
                                            viewPlatforms.toArray(false);

        for (int i=viewPlatforms.arraySize()- 1; i>=0; i--) {
            vpLists[i].schedSphere.getWithLock(tempSphere);
            if (tempSphere.intersect(region)) {
                return true;
            }
        }
        return false;
    }

    void loadSound(SoundRetained sound, boolean forceLoad) {
// QUESTION: should not be calling into soundScheduler directly???
        MediaContainer mediaContainer = sound.getSoundData();
        ViewPlatformRetained vpLists[] = (ViewPlatformRetained [])
                                            viewPlatforms.toArray(false);

        for (int i=viewPlatforms.arraySize()- 1; i>=0; i--) {
            View[] views = vpLists[i].getViewList();
            for (int j=(views.length-1); j>=0; j--) {
			View v = views[j];
// XXXX: Shouldn't this be done with messages??
                v.soundScheduler.loadSound(sound, forceLoad);
            }
        }
    }

    void enableSound(SoundRetained sound) {
        ViewPlatformRetained vpLists[] = (ViewPlatformRetained [])
                                            viewPlatforms.toArray(false);
        for (int i=viewPlatforms.arraySize()- 1; i>=0; i--) {
            View[] views = vpLists[i].getViewList();
            for (int j=(views.length-1); j>=0; j--) {
			View v = views[j];
                v.soundScheduler.enableSound(sound);
            }
        }
    }

    void muteSound(SoundRetained sound) {
        ViewPlatformRetained vpLists[] = (ViewPlatformRetained [])
                                            viewPlatforms.toArray(false);
        for (int i=viewPlatforms.arraySize()- 1; i>=0; i--) {
            View[] views = vpLists[i].getViewList();
            for (int j=(views.length-1); j>=0; j--) {
			View v = views[j];
                v.soundScheduler.muteSound(sound);
            }
        }
    }

    void pauseSound(SoundRetained sound) {
        ViewPlatformRetained vpLists[] = (ViewPlatformRetained [])
                                            viewPlatforms.toArray(false);
        for (int i=viewPlatforms.arraySize()- 1; i>=0; i--) {
            View[] views = vpLists[i].getViewList();
            for (int j=(views.length-1); j>=0; j--) {
			View v = views[j];
                v.soundScheduler.pauseSound(sound);
            }
        }
    }

    // Implementation be needed.
    void processSwitchChanged(J3dMessage m) {
        /*
        SoundRetained sound;
        LeafRetained leaf;
        UnorderList arrList;
        int size;
        Object[] nodes;

        UpdateTargets targets = (UpdateTargets)m.args[0];
        arrList = targets.targetList[Targets.SND_TARGETS];

        if (arrList != null) {
            size = arrList.size();
            nodes = arrList.toArray(false);

            for (int i=size-1; i>=0; i--) {
                leaf = (LeafRetained)nodes[i];
                sound = (SoundRetained) leaf;
                if (sound.switchState.currentSwitchOn) {
                    // System.err.println("SoundStructure.switch on");
                    // add To Schedule List
                } else {
                    // System.err.println("SoundStructure.switch off");
                    // remove From Schedule List
                }
            }
        }
         */
    }

// How can active flag (based on View orientataion) be set here for all Views?!?

    UnorderList getSoundList(View view) {
	ArrayList l = (ArrayList)viewScopedSounds.get(view);
	// No sounds scoped to this view
	if (l == null)
	    return nonViewScopedSounds;
	UnorderList newS = (UnorderList) nonViewScopedSounds.clone();
	int size = l.size();
	for (int i = 0; i < size; i++) {
	    newS.add(l.get(i));
	}
	return newS;

    }
    UnorderList getSoundscapeList(View view) {
	ArrayList l = (ArrayList)viewScopedSoundscapes.get(view);
	// No sounds scoped to this view
	if (l == null)
	    return nonViewScopedSoundscapes;
	UnorderList newS = (UnorderList) nonViewScopedSoundscapes.clone();
	int size = l.size();
	for (int i = 0; i < size; i++) {
	    newS.add(l.get(i));
	}
	return newS;

    }


/*
// XXXX: how is immediate mode handled? below code taken from SoundSchedule
// Don't know how we'll process immediate mode sounds;
// Append immediate mode sounds to live sounds list
        if (graphicsCtx != null) {
            synchronized (graphicsCtx.sounds) {
                nImmedSounds = graphicsCtx.numSounds();
                numSoundsToProcess = nSounds + nImmedSounds;
                if (sounds.length < numSoundsToProcess) {
                    // increase the array length of sounds array list
                    // by added 32 elements more than universe list size
                    sounds = new SoundRetained[numSoundsToProcess + 32];
                }
                for (int i=0; i
            


© 2015 - 2024 Weber Informatics LLC | Privacy Policy